了解具有类和实例变量的属性语句

时间:2016-11-05 22:12:36

标签: python properties

所以我已经阅读了很多关于属性关键字的内容,我相信我已经掌握了它的要点。我遇到了这个例子

class PeopleHeight:
    def __init__(self, height = 150):
        self.height = height

    def convert_to_inches(self):
        return (self.height * 0.3937)

    def get_height(self):
        print("Inside the getter method")
        return self._height

    def set_height(self, value):
        if value < 0:
            raise ValueError("Height cannot be negative")
        print("Inside the setter method")
        self._height = value

    height = property(get_height, set_height) #---->CONFUSING

以及令我困惑的最后一句话

 height = property(get_height, set_height)

我理解属性声明有签名

property(fget=None, fset=None, fdel=None, doc=None)

我得到的是get_heightset_height。我理解高度是一个类变量(不是实例变量)但是get_heightset_height怎么样。我认为上面应该是

height = property(get_height, set_height)

但那是错误的语法,因为没有自我。我的问题是为什么当我们说:

时我们不会收到错误
property(get_height, set_height)

因为没有将get_height或set_height的定义设置为类范围。

1 个答案:

答案 0 :(得分:2)

执行class语句时,class正文中的语句都被执行,就好像它们都在函数内部一样。这会生成一组名称,然后用于设置类属性。请参阅class statement documentation

  

然后使用新创建的本地命名空间和原始全局命名空间,在新的执行框架中执行类的套件(请参阅命名和绑定)。 (通常,该套件主要包含函数定义。)当类的套件完成执行时,其执行框架将被丢弃,但其本地名称空间将被保存。 [4]然后使用基类的继承列表和属性字典的已保存本地名称空间创建类对象。

每个def ...语句都会生成分配给函数名称的函数对象,因此get_heightset_height都是只是函数,然后最终作为班上的属性。这同样适用于height = property(get_height, set_height)行;它访问名称get_heightset_height,调用property()可调用这些作为参数,结果分配给名称height

您可能会对以后的方法和property对象如何访问实例(方法中的self参数)感到困惑。函数和property对象都是descriptor objects;在实例上访问并在类上找到的任何描述符对象都是通过此协议自动绑定到实例。另请参阅Descriptor HOWTO

您可以在解释器中手动执行所有这些步骤:

>>> def get_height(self):
...     print("Inside the getter method")
...     return self._height
...
>>> def set_height(self, value):
...     if value < 0:
...         raise ValueError("Height cannot be negative")
...     print("Inside the setter method")
...     self._height = value
...
>>> height = property(get_height, set_height)
>>> height
<property object at 0x105758188>
>>> height.fget
<function get_height at 0x10560ce18>
>>> height.fset
<function set_height at 0x10567e730>
>>> class FakeHeight:
...     _height = 42
...
>>> instance = FakeHeight()
>>> height.__get__(instance)  # descriptor access
Inside the getter method
42
>>> height.__set__(instance, 82)  # descriptor setting
Inside the setter method
>>> instance._height
82