Flask源码系列6-描述符
本篇文章介绍Python中描述符的原理和使用。
flask源码:
1 | # config.py |
1.原理
在Python中,描述符是一种实现了特定方法的对象,这些方法是 __get__()
、__set__()
和 __delete__()
。描述符提供了一种强大的方法来重新定义属性的访问、设置和删除行为。它们是Python属性访问机制的基础,并且被用于实现属性、方法、静态方法和类方法。
描述符协议:描述符是实现了描述符协议的对象。描述符协议包括以下方法:
__get__(self, obj, type=None)
:访问属性时被调用。__set__(self, obj, value)
:设置属性时被调用。__delete__(self, obj)
:删除属性时被调用。
类型:描述符分为两类:
- 数据描述符:同时实现了
__get__()
和__set__()
方法。 - 非数据描述符:只实现了
__get__()
方法。
- 数据描述符:同时实现了
属性访问优先级:当使用点号访问属性时,Python解释器会根据以下规则查找属性:
- 如果对象的类定义了与属性同名的数据描述符,则调用数据描述符的
__get__()
方法。 - 如果对象本身的实例字典(
obj.__dict__
)中存在该属性,则直接返回该属性。 - 如果对象本身存在与属性同名的类属性,则直接返回该属性。
- 如果对象的类定义了与属性同名的非数据描述符,则调用非数据描述符的
__get__()
方法。 - 如果找不到属性,则查找对象的类的父类,重复上述过程。
__getattr__
方法:如果以上步骤都未能定位到属性,并且类定义了__getattr__
方法,那么将调用__getattr__(attr)
。如果未定义__getattr__
方法,那么将继续查找父类的__getattr__
方法。- 抛出
AttributeError
:如果所有这些尝试都失败了,将会抛出AttributeError
异常。
- 如果对象的类定义了与属性同名的数据描述符,则调用数据描述符的
2.使用
下面是一个用描述符实现数据验证的示例:
1 | class Validator: |
3.类的方法
类的方法用描述符实现简易版:
1 | class method: |
4.classmethod
classmethod用描述符实现简易版:
1 | class classmethod: |
5.staticmethod
staticmethod用描述符实现简易版:
1 | class staticmethod: |
6.property
property用描述符实现简易版:
1 | class property: |
- @property装饰器将x变成property的实例,即一个数据描述符,同时将装饰的方法赋值给了self.fget。此时x具备了setter方法;
- @x.setter装饰器将x变成property的实例,即一个数据描述符,同时将装饰的方法赋值给了self.fset,并保留了self.fget和self.fdel属性。此时,x具备了self.fget和self.fset方法,数据描述符能正常设置和取值。