Python描述符

Python描述符教程

描述符是任何新式 ,新式类是指继承自 type 或者 object 的类,这种类至少实现了 3 个特殊的方法 __get__, __set__, __delete__ 中的一个。而这 3 个特殊的方法充当描述符协议的作用。

同时实现了 __get____set__ 的类被称为数据描述符(data descriptor)。只实现了 __get__ 方法的类是非数据描述符(常用于方法,当然其他用途也是可以的)。

Python __get__ 原型详解

语法

Descriptor.__get__(self, instance, owner) --> value

说明

当我们用类或者实例来调用该属性时,Python 会返回 __get__ 函数的结果。

Python __set__ 原型详解

语法

Descriptor.__set__(self, instance, value) --> None

说明

当我们用实例来设置属性值时,Python 会调用该函数。对类没有限制作用。

Python __delete__ 原型详解

语法

Descriptor.__delete__(self, instance) --> None

说明

当我们用实例试图删除该属性时,Python 会调用该函数。对类没有限制作用。

Python描述符的访问详解

定义

Python 描述符的核心是 getattribute(),因为任何 实例属性 的访问都会调用到这个特殊的方法。这个方法被用来查找属性,同时也是一个代理,调用它可以进行属性的访问操作。

一般我们的类的 __getattribute__() 方法都是继承自 object,自己改写 __getattribute__() 是很危险的,也会阻止正常的描述符调用。

__getattribute__() 的 Python 描述原型如下:

def __getattribute__(self, key): "Emulate type_getattro() in Objects/typeobject.c" v = object.__getattribute__(self, key) if hasattr(v, '__get__'): return v.__get__(None, self) return v

说明

如果通过实例 ins 访问描述符,由 __getattribute__() 转化为:type(ins).__dict__['attr'].__get__(ins, type(ins),如果通过类 Class 访问描述符,由 __getattribute__() 转化为: Class.__dict__['attr'].__get__(None, Class)

案例

描述符 __get__ 方法

访问类属性时,会自动调用 __get__ 方法

print("嗨客网(www.haicoder.net)") class Descriptor(object): def __init__(self): self.name = 'anonymous' def __get__(self, instance, owner): print('instance: %s' % instance) print('owner: %s' % owner) print("Invoke __get__: %s" % self.name) return self.name class Person(object): name = Descriptor() # 通过类Person访问 print(Person.name) print('---------------------------------------') print(Person.__dict__['name'].__get__(None, Person))

程序运行后,控制台输出如下:

53_python类描述器.png

定义了一个 Descriptor 类,该类有一个构造函数和一个 __get__ 方法,接着,我们定义了一个 Person 类,Person 类里面有一个类属性 name,类属性 name 使用 Descriptor 类初始化。

最后,我们分别使用类名访问 Person 类的属性和使用 dict 访问 name 属性,我们发现,两种方式,都调用了 Descriptor 类的 __get__ 方法。

描述符 __get__ 方法

使用类实例访问类属性时,会自动调用 __get__ 方法

print("嗨客网(www.haicoder.net)") class Descriptor(object): def __init__(self): self.name = 'anonymous' def __get__(self, instance, owner): print('instance: %s' % instance) print('owner: %s' % owner) print("Invoke __get__: %s" % self.name) return self.name class Person(object): name = Descriptor() user = Person() # 通过实例user访问, `owner`访问描述符实例的对象。`instance`则是访问描述符实例的实例 print(user.name) print('-----------------------------------') print(type(user).__dict__['name'].__get__(user, type(user)))

程序运行后,控制台输出如下:

54_python类描述器.png

我们使用类的实例访问类属性时,同样调用了 __get__ 方法。

描述符 __set__ 方法

设置类属性时,会自动调用 __set__ 方法

print("嗨客网(www.haicoder.net)") class Descriptor(object): def __init__(self): self.name = 'anonymous' def __set__(self, instance, name): print("invoke __set__: %s" % name) self.name = name.title() class Person(object): name = Descriptor() user = Person() user.name = 'jack'

程序运行后,控制台输出如下:

55_python类描述器.png

当我们给类实例的实例属性赋值时,会自动调用 __set__ 方法。

描述符 __del__ 方法

设置类属性时,会自动调用 __set__ 方法

print("嗨客网(www.haicoder.net)") class Descriptor(object): def __init__(self): self.name = 'anonymous' def __delete__(self, instance): print("Invoke __delete__: %s" % self.name) del self.name class Person(object): name = Descriptor() user = Person() del user.name

程序运行后,控制台输出如下:

56_python类描述器.png

当我们使用 del 删除类的实例属性时,会自动调用 __del__ 方法。

Python描述符教程总结

描述符是任何新式类,新式类是指继承自 type 或者 object 的类,这种类至少实现了 3 个特殊的方法 __get__, __set__, __delete__ 中的一个。而这 3 个特殊的方法充当描述符协议的作用。

同时实现了 __get____set__ 的类被称为数据描述符(data descriptor)。只实现了 __get__ 方法的类是非数据描述符(常用于方法,当然其他用途也是可以的)。