Python 黑魔法 — 描述器(descriptor)
admin
2023-07-31 00:44:46
0

Python 黑魔法—描述器(descriptor)

Python黑魔法,前面已经介绍了两个魔法,装饰器和迭代器,通常还有个生成器。生成器固然也是一个很优雅的魔法。生成器更像是函数的行为。而连接类行为和函数行为的时候,还有一个描述器魔法,也称之为描述符。

我们不止一次说过,Python的优雅,很大程度在于如何设计成优雅的API。黑魔法则是一大利器。或者说Python的优雅很大程度上是建立在这些魔法巧技基础上。

何谓描述器

当定义迭代器的时候,描述是实现迭代协议的对象,即实现__iter__方法的对象。同理,所谓描述器,即实现了描述符协议,即__get__, __set__, 和 __delete__方法的对象。

单看定义,还是比较抽象的。talk is cheap。看代码吧:

12345678910111213141516171819202122 class WebFramework(object):    def __init__(self, name=\’Flask\’):        self.name = name     def __get__(self, instance, owner):        return self.name     def __set__(self, instance, value):        self.name = value  class PythonSite(object):     webframework = WebFramework() In [1]: PythonSite.webframeworkOut[1]: \’Flask\’ In [2]: PythonSite.webframework = \’Tornado\’ In [3]: PythonSite.webframeworkOut[3]: \’Tornado\’

定义了一个类WebFramework,它实现了描述符协议__get____set__,该对象(类也是对象,一切都是对象)即成为了一个描述器。同时实现__get____set__的称之为资料描述器(data descriptor)。仅仅实现__get__的则为非描述器。两者的差别是相对于实例的字典的优先级。

如果实例字典中有与描述器同名的属性,如果描述器是资料描述器,优先使用资料描述器,如果是非资料描述器,优先使用字典中的属性。

描述器的调用

对于这类魔法,其调用方法往往不是直接使用的。例如装饰器需要用 @ 符号调用。迭代器通常在迭代过程,或者使用 next 方法调用。描述器则比较简单,对象属性的时候会调用。

1234 In [15]: webframework = WebFramework() In [16]: webframework.__get__(webframework, WebFramework)Out[16]: \’Flask\’

描述器与对象属性

OOP的理论中,类的成员变量包括属性和方法。那么在Python里什么是属性?修改上面的PythonSite类如下:

12345678 class PythonSite(object):     webframework = WebFramework()     version = 0.01     def __init__(self, site):        self.site = site

这里增加了一个version的类属性,以及一个实例属性site。分别查看一下类和实例对象的属性:

1234567891011121314151617181920212223 In [1]: pysite = PythonSite(\’ghost\’) In [2]: vars(PythonSite).items()Out[2]:[(\’__module__\’, \’__main__\’), (\’version\’, 0.01), (\’__dict__\’, \’__dict__\’ of \’PythonSite\’ objects>), (\’webframework\’, <__main__.WebFramework at 0x10d55be90>), (\’__weakref__\’, \’__weakref__\’ of \’PythonSite\’ objects>), (\’__doc__\’, None), (\’__init__\’, __main__.__init__>)] In [3]: vars(pysite)Out[3]: {\’site\’: \’ghost\’}In [4]: PythonSite.__dict__Out[4]:{\’__dict__\’: \’__dict__\’ of \’PythonSite\’ objects>, \’__doc__\’: None, \’__init__\’: __main__.__init__>, \’__module__\’: \’__main__\’, \’__weakref__\’: \’__weakref__\’ of \’PythonSite\’ objects>, \’version\’: 0.01, \’webframework\’: <__main__.WebFramework at 0x10d55be90>}>

vars方法用于查看对象的属性,等价于对象的__dict__内容。从上面 符。

我们不止一次说过,Python的优雅,很大程度在于如何设计成优雅的API。黑魔法则是一大利器。或者说Python的优雅很大程度上是建立在这些魔法巧技基础上。

何谓描述器

当定义迭代器的时候,描述是实现迭代协议的对象,即实现__iter__方法的对象。同理,所谓描述器,即实现了描述符协议,即__get__, __set__, 和 __delete__方法的对象。

单看定义,还是比较抽象的。talk is cheap。看代码吧:

12345678910111213141516171819202122 class WebFramework(object):    def __init__(self, name=\’Flask\’):        self.name = name     def __get__(self, instance, owner):        return self.name     def __set__(self, instance, value):        self.name = value  class PythonSite(object):     webframework = WebFramework() In [1]: PythonSite.webframeworkOut[1]: \’Flask\’ In [2]: PythonSite.webframework = \’Tornado\’ In [3]: PythonSite.webframeworkOut[3]: \’Tornado\’

定义了一个类WebFramework,它实现了描述符协议__get____set__,该对象(类也是对象,一切都是对象)即成为了一个描述器。同时实现__get____set__的称之为资料描述器(data descriptor)。仅仅实现__get__的则为非描述器。两者的差别是相对于实例的字典的优先级。

如果实例字典中有与描述器同名的属性,如果描述器是资料描述器,优先使用资料描述器,如果是非资料描述器,优先使用字典中的属性。

描述器的调用

对于这类魔法,其调用方法往往不是直接使用的。例如装饰器需要用 @ 符号调用。迭代器通常在迭代过程,或者使用 next 方法调用。描述器则比较简单,对象属性的时候会调用。

1234 In [15]: webframework = WebFramework() In [16]: webframework.__get__(webframework, WebFramework)Out[16]: \’Flask\’

描述器与对象属性

OOP的理论中,类的成员变量包括属性和方法。那么在Python里什么是属性?修改上面的PythonSite类如下:

12345678 class PythonSite(object):     webframework = WebFramework()     version = 0.01     def __init__(self, site):        self.site = site

这里增加了一个version的类属性,以及一个实例属性site。分别查看一下类和实例对象的属性:

1234567891011121314151617181920212223 In [1]: pysite = PythonSite(\’ghost\’) In [2]: vars(PythonSite).items()Out[2]:[(\’__module__\’, \’__main__\’), (\’version\’, 0.01), (\’__dict__\’, \’__dict__\’ of \’PythonSite\’ objects>), (\’webframework\’, <__main__.WebFramework at 0x10d55be90>), (\’__weakref__\’, \’__weakref__\’ of \’PythonSite\’ objects>), (\’__doc__\’, None), (\’__init__\’, __main__.__init__>)] In [3]: vars(pysite)Out[3]: {\’site\’: \’ghost\’}In [4]: PythonSite.__dict__Out[4]:{\’__dict__\’: \’__dict__\’ of \’PythonSite\’ objects>, \’__doc__\’: None, \’__init__\’: __main__.__init__>, \’__module__\’: \’__main__\’, \’__weakref__\’: \’__weakref__\’ of \’PythonSite\’ objects>, \’version\’: 0.01, \’webframework\’: <__main__.WebFramework at 0x10d55be90>}>

vars方法用于查看对象的属性,等价于对象的__dict__内容。从上面 ayon-5812b20437973263109958-21\”>

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...