Python 描述符是什么?以及如何实现
2018-06-18 02:54:00来源:未知 阅读 ()
先看一个例子,@property。被@property修饰的成员函数,将变为一个描述符。这是最简单的创建描述符的方式。
class Foo:
@property
def attr(self):
print('getting attr')
return 'attr value'
def bar(self): pass
foo = Foo()
上面这个例子中, attr
是类 Foo
的一个成员函数,可通过语句 foo.attr()
被调用。 但当它被 @property
修饰后,这个成员函数将不再是一个函数,而变为一个描述符。 bar
是一个未被修饰的成员函数。 type(Foo.attr)
与 type(Foo.bar)
的结果分别为:
<type 'property'>
<type 'instancemethod'>
attr
的类型为 property
(注:一个 property
类型的对象总是一个描述符), bar
的类型为 instancemethod
,也即一个常规的成员函数。
此时 attr
将无法再被调用,当尝试调用它时,语句 foo.attr()
将抛出错误:
TypeError: 'str' object is not callable
让我们来理解这个错误。
首先来看 foo.attr
的值:
attr value
其类型 type(foo.attr)
:
str
foo.attr
的类型为 str
,因此便有了以上的错误,一个 str
对象无法被调用。其值为'attr value',正好是原始 attr
函数的返回值。 因此语句 foo.attr
实际上触发了原始 attr
函数的调用,并且将函数的返回值作为其值。实际上语句 print(foo.attr)
的输出为:
getting attr
attr value
进一步验证了执行语句 foo.attr
时,原始的 attr
函数被调用。
发生了什么?当执行一个访问对象属性的语句 foo.attr
时,结果一个函数调用被触发!这便是描述符的作用:将属性访问转变为函数调用,并由这个函数来控制这个属性的值(也即函数的返回值),以及在返回值前做定制化的操作。此时可以给描述符一个简要定义:
描述符是类的一个属性,控制类实例对象访问这个属性时如何返回值及做哪些额外操作
这留给程序员的空间是巨大的。。
描述符协议
任何实现了描述符协议的类都可以作为描述符类。描述符协议为一组成员函数定义,包括:
函数 | 作用 | 返回值 | 是否必须 |
---|---|---|---|
__get__(self, obj, type) |
获取属性值 | 属性的值 | 是 |
__set__(self, obj, value) |
设置属性的值 | None | 否 |
__delete__(self, obj) |
删除属性 | None | 否 |
如果一个类实现了以上成员函数,则它便是一个描述符类,其实例对象便是一个描述符
下面是一个自定义的描述符的实现。
class MyDescriptor:
def __init__(self):
self.data = None
def __get__(self, obj, type):
print('get called')
return self.data
def __set__(self, obj, value):
print('set called')
self.data = value
def __delete__(self, obj):
print('delete called')
del self.data
class Foo:
attr = MyDescriptor()
foo = Foo()
示例中 MyDescriptor
实现了描述符协议(也即实现了 __get__, __set__, __delete__
函数),因此其为一个描述符类。 Foo
的 attr
属性为 MyDescriptor
类的实例对象,因此它是一个描述符。
print(foo.attr)
的输出为:
get called
None
可见当访问 foo
的 attr
属性时, MyDescriptor
的 __get__
函数被调用。
foo.attr = 'new value' 的输出为:
set called
可见当为 attr
设置一个新值时, MyDescriptor
的 __set__
函数被调用。
再运行 print(foo.attr)
,输出为:
get called
new value
可见新值已被设置。
del foo.attr
的输出为:
delete called
可见当为删除属性 attr
时, MyDescriptor
的 __delete__
函数被调用。
再执行 print(foo.attr)
, AttributeError
被抛出:
get called
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "1.py", line 6, in __get__
return self.data
AttributeError: 'MyDescriptor' object has no attribute 'data'
可见属性 attr
已被删除。
参数意义
__get__(self, obj, type)
函数各个参数的意义为:
参数 | 意义 | 例子中的对应 |
---|---|---|
self | 描述符对象本身 | Foo.attr |
obj | 使用描述符的对象实例 | foo |
type | obj的类型 | Foo |
__set__(self, obj, value)
函数的self和obj参数的意义同 __get__
,value的意义为:
参数 | 意义 | 例子中的对应 |
---|---|---|
value | 属性的新值 | 'new value' |
__delete__(self, obj)
函数的self和obj参数的意义同 __get__
。
(全文完)
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:python网络编程(三)
- python3基础之“术语表(2)” 2019-08-13
- python3 之 字符串编码小结(Unicode、utf-8、gbk、gb2312等 2019-08-13
- Python3安装impala 2019-08-13
- 小白如何入门 Python 爬虫? 2019-08-13
- python_字符串方法 2019-08-13
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash