Python属性如何工作?


78

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

@property
def hello(): return "Hello, world!"

hello  # <property object at 0x9870a8>

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

class Foo(object):
   @property
   def hello(self): return "Hello, world!"

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

我注意到未绑定Foo.hello仍然是property对象,因此类实例化必须在做魔术,但是那是什么魔术呢?



很好地映射两个问题@MartinThoma,谢谢!
库山Gunasekera

3
@MartinThoma max recursion depth exceeded...哈哈
Zain Arshad

Answers:


53

正如其他人指出的那样,它们使用称为描述符的语言功能。

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

  • 如果在实例上访问了描述符,则该实例作为适当的参数传递,并且owner是该实例的
  • 当通过类访问它时,instance则为None且仅owner通过。该property对象认识到这一点并返回self

除了“描述符”方法外,另请参阅《语言指南》中有关实现描述符调用描述符的文档。


24

为了使@properties正常工作,该类必须是object的子类。当该类不是对象的子类时,则首次尝试访问setter时,它实际上会创建一个名称较短的新属性,而不是通过setter进行访问。

以下无法正常工作。

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

以下将正常工作

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

30
应该意识到,从Python 3开始,不再需要从对象继承。
DeFazer's

8
更准确地说,在Python 3中,类默认情况下是从object继承的,因此无需在代码中明确编写。
Nathaniel Verhaaren

12

属性是描述符,描述符在类实例的成员中表现特别。简而言之,如果a是type的实例A,并且A.foo是描述符,则a.foo等效于A.foo.__get__(a)


实际上,它们似乎也可以使用旧式类(在Python 2.7中)。但感谢您的链接,将阅读。
弗雷德·富

请注意,方法签名__get__()不正确。它有两个参数(除了self之外)。否则很好的解释。
蒂姆·耶茨

@larsmans:在链接的页面上:“请注意,描述符仅针对新样式对象或类调用。” 我还记得我曾经尝试过旧风格的课。
Sven Marnach

@Tim:第二个参数是可选的。
Sven Marnach

2
@larsmans:我做了一些快速测试。描述符本身的类型必须是新样式的类,否则它将不起作用。包含描述符的类无关紧要。可以以任何一种方式阅读以上引用。
Sven Marnach

2

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


15
我当然理解这种情况下dw的原因,这个答案和一个被接受的答案都没有真实的解释,基本上只是链接。尽管在某些解决错误的情况下这已足够,但OP似乎正在寻求对此问题的人为解释。
Morgan Wilde
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.