python 描述符类_python的黑魔法--描述符
python的黑魔法
描述符
官方定义:python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有 get(), set(), 和delete()。如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符。简单地说: 某个类,只要是内部定义了方法 __get__, __set__, __delete__ 中的一个或多个,就可以称为描述符
但是描述符有什么作用呢
描述符的作用是用来代理一个类的属性。 描述符单独存在没有意义,一般描述符就是某个实例的属性,当访问该属性时,就会调用描述符的__get__方法,而修改会调用__set__方法,删除会调用__delete__方法;
首先定义一个描述符
class Descriptors:
def __init__(self, key):
self.name = key
def __get__(self, instance, owner):
print("执行Descriptors的get")
if instance:
return instance.__dict__['name']
return self.name
def __set__(self, instance, value):
print("执行Descriptors的set")
if not isinstance(value, str):
raise TypeError("名字必须为字符串")
if instance:
instance.__dict__['name'] = value
else:
self.name = value
class User():
name = '小明'
def __init__(self, name):
self.name = name
首先看一下类属性
User.name
'小明'
然后看一下实例属性
u1 = User(11)
u1.name,User.name
(11, '小明')
可以看到类属性与实例属性互不干扰,然后再看看使用描述符会怎么样
class User():
name = Descriptors('小明')
def __init__(self, name):
self.name = name
看一下类属性
User.name
执行Descriptors的get
'小明'
u1 = User(11)
执行Descriptors的set
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 u1 = User(11)
in __init__(self, name)
2 name = Descriptors('小明')
3 def __init__(self, name):
----> 4 self.name = name
in __set__(self, instance, value)
12 print("执行Descriptors的set")
13 if not isinstance(value, str):
---> 14 raise TypeError("名字必须为字符串")
15 if instance:
16 instance.__dict__['name'] = value
TypeError: 名字必须为字符串
u1 = User('小王')
执行Descriptors的set
u1.name,User.name
执行Descriptors的get
执行Descriptors的get
('小王', '小李')
User.name=Descriptors('小李')
u1.name,User.name
执行Descriptors的get
执行Descriptors的get
('小王', '小李')
u2 = User('小明')
执行Descriptors的set
u1.name,User.name, u2.name
执行Descriptors的get
执行Descriptors的get
执行Descriptors的get
('小王', '小李', '小明')
可以看到虽然类属性与实例属性互不干扰,但是实例属性会调用类属性的魔法方法,前提是属性名字必须与描述符同名
所以可以通过描述符限定实例属性,对实例属性进行某些操作。感觉和装饰器很像
实现描述符的功能还有另一种方式,那就是装饰器
class User():
def __init__(self, x):
self.name = x
@property
def name(self):
return self.x
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError("名字必须为字符串")
self.x = value
u1 = User(11)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 u1 = User(11)
in __init__(self, x)
1 class User():
2 def __init__(self, x):
----> 3 self.name = x
4 @property
5 def name(self):
in name(self, value)
8 def name(self, value):
9 if not isinstance(value, str):
---> 10 raise TypeError("名字必须为字符串")
11 self.x = value
TypeError: 名字必须为字符串
u1 = User('小王')
u1.name
'小王'
这种方法其实底层也是通过描述符实现的,而且描述符比这种方法适应性更大。
描述符的分类
描述符分两种: + 数据描述符:实现了__get__ 和 __set__ 两种方法的描述符 + 非数据描述符:只实现了__get__ 一种方法的描述符 当我们对一个实例属性进行访问时,Python 会按 obj.dict → type(obj).dict → type(obj)的父类.dict 顺序进行查找,但是引入描述符之后,会改变这个搜索过程《流畅的Python》中写到,“Python存取属性的方式特别不对等,通过实例读取属性时,通常返回的是实例中定义的属性;但是,如果实例中没有指定的属性,那么会获取类属性。而为实例中的属性赋值时,通常会在实例中创建属性,根本不影响类。这种 不对等的处理方式对描述符也有影响。”
class Age:
def __init__(self, key):
self.age = key
def __get__(self, instance, owner):
print("执行Age的get")
if instance:
return instance.__dict__['age']
return self.age
def __set__(self, instance, value):
print("执行Age的set")
if not isinstance(value, int):
raise TypeError("年纪必须为整型")
if value<=0:
raise TypeError("年纪必须大于1")
if instance:
instance.__dict__['age'] = value
else:
self.age = value
class Nick:
def __init__(self, key):
self.nick = key
def __get__(self, instance, owner):
print("执行Nick的get")
if instance:
return instance.__dict__['nick']
return self.nick
class User():
name = Descriptors('小明')
age = Age(1)
nick = Nick('ming')
def __init__(self, name, age, nick):
self.name = name
self.age = age
self.nick = nick
u1 = User('小李', 10, 'sun')
执行Descriptors的set
执行Age的set
u1.age
执行Age的get
10
u1.nick
'sun'
因为Nick没有set的魔法方法,所以当实例中对nick属性赋值时,会直接在实例中赋值,所以这类查找的顺序是:实例的属性->找dict->找描述符,这些会更快一下如果实例字典中有与描述符同名的属性,如果描述符是数据描述符,优先使用数据描述符,如果是非数据描述符,优先使用字典中的属性。
python 描述符类_python的黑魔法--描述符相关推荐
- python编写ATM类_Python中编写类的各种技巧和方法
有关 Python 内编写类的各种技巧和方法(构建和初始化.重载操作符.类描述.属性访问控制.自定义序列.反射机制.可调用对象.上下文管理.构建描述符对象.Pickling).你可以把它当作一个教程, ...
- python如何定义类_python中定义类
广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 类的定义python中,定义类是通过class关键字,例如我们定义一个存储学生信 ...
- python如何定义类_Python 面向对象
Python 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触过 ...
- python中定制类_python定制类__str__(实例详解)
在接下来的文章中,让我们明白什么是python中的自定义类.学习什么是python的自定义类,python定制类可以扮演何种角色在python编程.当你看到像__xxx__ __slots__变量或函 ...
- python如何定义类_Python中类的定义、继承及使用对象实例详解
本文实例讲述了Python中类的定义.继承及使用对象的方法.分享给大家供大家参考.具体分析如下: Python编程中类的概念可以比作是某种类型集合的描述,如"人类"可以被看作一个类 ...
- python查看所有异常类_Python调试常见异常汇总
以下就是常见的异常以及其中文描述. BaseException --所有异常的基类 SystemExit --解释器请求退出 KeyboardInterrupt --用户中断执行(通常是输入^C) E ...
- python飞机大战类_Python版飞机大战
前面学了java用java写了飞机大战这次学完python基础后写了个python版的飞机大战,有兴趣的可以看下. 父类是飞行物类是所有对象的父类,setting里面是需要加载的图片,你可以换称自己的 ...
- python模块和类_Python类、模块、包的区别
类 类的概念在许多语言中出现,很容易理解.它将数据和操作进行封装,以便将来的复用. 模块 模块,在Python可理解为对应于一个文件.在创建了一个脚本文件后,定义了某些函数和变量.你在其他需要这些功能 ...
- python如何定义类_Python class定义类,Python类的定义(入门必读)
在面向对象的程序设计过程中有两个重要概念:类(class)和对象(object,也被称为实例,instance),其中类是某一批对象的抽象,可以把类理解成某种概念:对象才是一个具体存在的实体.从这个意 ...
最新文章
- LabVIEW读写各类格式图像的方法(基础篇—1)
- ‘%.2f‘ 与 ‘{:.2f}‘.format(w) 区别
- Serendipity解决IE缓存为0
- android ImageButton显示本地图片
- java中doloop语句_Java中的do-while循环——通过示例学习Java编程(11)
- Manitest: Are classifiers really invariant?论文解读
- 没有实际的工作经验,如何面试Linux运维工程师?
- JS-获取当前URL的参数
- java过滤敏感词汇
- Python学习 Task01 :变量,运算符,与数据类型
- web服务器集群-------Apache网页优化 (1)网页压缩
- blos硬盘启动台式计算机,电脑如何bios设置硬盘启动顺序?掌握这6大类型是关键!...
- 【OCP】小麦苗OCP(包括11g、12c、18c、19c等)网络班早已开讲,注重实践,报名一次,终身可免费升级学习,推荐有红包...
- kali linux CC搭建教程,kali linux初次安装配置
- 产品经理之如何快速阐释产品价值(FABE模型)
- R语言GARCH-DCC模型和DCC(MVT)建模估计
- 李宏毅svm_【李宏毅机器学习笔记】 18、支持向量机(Support Vector Machine,SVM)...
- 关于zigbee的一些术语
- 华为2288H v5服务器配置JBOD(硬盘直通)
- 怎么制作微信gif表情?这几个方法简单好用
热门文章
- Maven学习总结(27)——Maven自定义打包插件maven-assembly-plugin详解
- Windows学习总结(15)——Notepad++ 快捷键大全
- 电信主机托管费用_电信服务器托管价格
- Muse-UI +Vue2.0框架开发环境搭建
- 安装 Android Studio 2.3 详细过程及错误解决
- 使用wampserver部署的织梦站点无法登录后台
- [工具类]文件或文件夹xx已存在,则重命名为xx(n)(2)
- 最大子矩阵问题悬线法 学习小结
- flutter: 根视图、根元素与根渲染
- windows下的workon env