python属性如何工作?

How do Python properties work?

我已经成功地使用了python属性,但我不知道它们如何工作。如果我取消了类外的属性的引用,我只得到一个property类型的对象:

1
2
3
4
@property
def hello(): return"Hello, world!"

hello  # <property object at 0x9870a8>

但是如果我将一个属性放在类中,则行为会非常不同:

1
2
3
4
5
class Foo(object):
   @property
   def hello(self): return"Hello, world!"

Foo().hello # 'Hello, world!'

我注意到未绑定的Foo.hello仍然是property对象,所以类实例化一定是在做魔法,但那是什么魔法?


正如其他人所指出的,他们使用一种称为描述符的语言特性。

通过类Foo.hello访问实际属性对象时返回实际属性对象的原因在于该属性如何实现__get__(self, instance, owner)特殊方法:

  • 如果在实例上访问描述符,那么该实例将作为适当的参数传递,并且owner是该实例的类。
  • 当它通过类访问时,那么instance为无,只有owner被传递。property对象识别出这一点并返回self

除了如何使用描述符之外,请参阅《语言指南》中有关实现描述符和调用描述符的文档。


为了使@properties正常工作,类需要是对象的子类。当类不是对象的子类时,那么第一次尝试访问setter时,它实际上会生成一个名称较短的新属性,而不是通过setter访问。

以下各项工作不正常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class C(): # <-- Notice that object is missing

    def __init__(self):
        self._x = None

    @property
    def x(self):
        print 'getting value of x'
        return self._x

    @x.setter
    def x(self, x):
        print 'setting value of x'
        self._x = x

>>> c = C()
>>> c.x = 1
>>> print c.x, c._x
1 0

以下各项工作正常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class C(object):

    def __init__(self):
        self._x = None

    @property
    def x(self):
        print 'getting value of x'
        return self._x

    @x.setter
    def x(self, x):
        print 'setting value of x'
        self._x = x

>>> c = C()
>>> c.x = 1
setting value of x
>>> print c.x, c._x
getting value of x
1 1


属性是描述符,当类实例的成员时,描述符的行为特别。简而言之,如果aa类型的实例,而A.foo是描述符,那么A.foo等于A.foo.__get__(a)


property对象只实现了描述符协议:http://docs.python.org/howto/descriptor.html