简体   繁体   English

Python的属性装饰器不能按预期工作

[英]Python's property decorator does not work as expected

class Silly:
    @property
    def silly(self):
        "This is a silly property"
        print("You are getting silly")
        return self._silly

    @silly.setter
    def silly(self, value):
        print("You are making silly {}".format(value))
        self._silly = value

    @silly.deleter
    def silly(self):
        print("Whoah, you killed silly!")
        del self._silly

s = Silly()
s.silly = "funny"
value = s.silly
del s.silly

But it does not print "You are getting silly", "You are making silly funny",... as expected. 但它没有打印出“你变得愚蠢”,“你正在制造愚蠢的搞笑”,......正如预期的那样。 Don't know why. 不知道为什么。 Can you have me figure out, folks? 亲爱的,你能让我弄清楚吗?

Thanks in advance! 提前致谢!

The property decorator only works with new-style classes ( see also ). property装饰器仅适用于新式类另请参见 )。 Make Silly extend from object explicitly to make it a new-style class. Make Silly明确地从object扩展,使其成为一个新式的类。 (In Python 3, all classes are new-style classes) (在Python 3中,所有类都是新式类)

class Silly(object):
    @property
    def silly(self):
        # ...
    # ...

As you most likely are aware of the correct method to add properties would be to use: 您很可能知道添加属性的正确方法是使用:

@property
def silly(self):
    return self._silly


@silly.setter:
def silly(self, value):
    self._silly = value

But this requires new style classes, that is that somewhere in the chain there is supposed to be a class ParentClass(object): . 但是这需要新的样式类,即链中的某个地方应该是一个class ParentClass(object): The similar option of using silly = property(get_silly, set_silly) has the same requirement. 使用silly = property(get_silly, set_silly)的类似选项具有相同的要求。

However, there is another option, and that is to use a corresponding private variable, like self._silly , and override the __getattr__ and __setattr__ methods: 但是,还有另一种选择,即使用相应的私有变量,如self._silly ,并覆盖__getattr____setattr__方法:

def __getattr__(self, name): 
    """Called _after_ looking in the normal places for name."""  

    if name == 'silly':
        self._silly
    else:
        raise AttributeError(name)


def __setattr__(self, name, value):
    """Called _before_ looking in the normal places for name."""
    if name == 'silly':
        self.__dict__['_silly'] = value
    else:
        self.__dict__[name] = value

Notice how __getattr__ will be called after checking for other attributes, but that __setattr__ is called before checking for other attributes. 注意检查其他属性如何调用__getattr__ ,但检查其他属性之前调用__setattr__ Therefore the former can and should raise an error if not an accepted attribute, and the latter should set the attribute. 因此,如果不是可接受的属性,前者可以而且应该引发错误,后者应该设置属性。 Do not use self._silly = value within __setattr__ as that would cause infinite recursion. 不要使用self._silly = value__setattr__因为这将导致无限递归。

Also note that since we're dealing with old style classes here, you should actually use the dict method, and not the newer baseclass.__setattr__(self, attr, value) , see docs . 另请注意,由于我们在这里处理旧样式类,您实际上应该使用dict方法,而不是更新的baseclass.__setattr__(self, attr, value) ,请参阅docs A similar __delattr__() does also exist, if you want it. 如果你需要,也会存在类似的__delattr__()

Using this code, you can now do stuff like: 使用此代码,您现在可以执行以下操作:

i_am = Silly()
i_am.silly = 'No, I'm clever'
print i_am.silly

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM