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'
原文地址:https://www.cnblogs.com/paomaliuju/p/5140708.html