Python描述符:property()函数的小秘密
描述符:将某种特殊类型的类的实例指派给另一个类的属性(注意:这里是类属性,而不是对象属性)。而这种特殊类型的类就是实现了__get__,__set__,__delete__这三个方法中的一个或多个的新式类(即继承object)。其中,__get__,__set__,__delete__与__getattr__,__setattr__,__delattr__是很相似的,但是前面3个我们称之为属于描述符的属性方法。
__get__(self, instance, owner)
- 用于访问属性,它返回属性的值
__set__(self, instance, value)
- 将在属性分配操作中(赋值)调用,不返回任何内容
__delete__(self, instance)
- 控制删除操作,不返回任何内容
class MyDescriptor: def __get__(self, instance, owener): print('getting...', self, instance, owener) def __set__(self, instance, value): print('settiong...', self, instance, value) def __delete__(self, instance): print('deleting...', self, instance) class Test: x = MyDescriptor() >>> test = Test() >>> test.x getting... <__main__.MyDescriptor object at 0x0000000002D6A6A0> <__main__.Test object at 0x0000000002D886A0> <class '__main__.Test'> >>> test <__main__.Test object at 0x0000000002D886A0> >>> Test <class '__main__.Test'>
以上代码中,MyDescriptor类就是描述符类。其中__get__,__set__,__delete__方法中的self是指MyDescriptor类本身的实例对象;instance参数是指属性拥有者的类的实例(本例中是test);__get__第三个参数owner是指属性拥有者的类对象本身(本例中是Test)。其实,property()函数就是一个描述符类,以下就是自定义的property()函数:
class MyProperty: def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset self.fdel = fdel def __get__(self, instance, owner): return self.fget(instance) def __set__(self, instance, value): self.fset(instance, value) def __delete__(self, instance): self.fdel(instance) class C: def __init__(self): self._x = None def getX(self): return self._x def setX(self, value): self._x = value def delX(self): del self._x x = MyProperty(getX, setX, delX) >>> c = C() >>> c.x = 'x-man' >>> c.x 'x-man' >>> del c.x >>> c.x Traceback (most recent call last): File "<pyshell#79>", line 1, in <module> c.x File "<pyshell#72>", line 7, in __get__ return self.fget(instance) File "<pyshell#74>", line 5, in getX return self._x AttributeError: 'C' object has no attribute '_x'