是否正确地说python中属性的setter函数就像重载赋值运算符一样?

时间:2019-07-08 16:28:18

标签: python

我才刚刚开始学习python中的OOP主题,并且遇到了一些麻烦的主题,例如装饰器/属性以及python中所有“私有”方法的技巧。

可以肯定地说,使用 @property 就像使用属性一样,但是在幕后有一个函数可以执行某些操作吗? (例如,检查输入)
另外,使用 @ is_barking.setter 就像重载其他语言(例如C ++)的赋值运算符一样吗?因为我还可以检查输入内容之类的东西

这是代码:

class Dog():
    def __init__(self,name):
        self.name = name

    @property
    def is_barking(self):
        try:
            return self._is_barking
        except AttributeError as error:
            self._is_barking = False
            return self._is_barking

    @is_barking.setter
    def is_barking(self,value):
        self._is_barking = value


def main():
    rexi = Dog("rexi")
    print(rexi.is_barking)
    rexi.is_barking = True
    print(rexi.is_barking)

main()

>> False
>> True

非常感谢您!

1 个答案:

答案 0 :(得分:1)

是的,这是正确的。设置器使您可以仅拦截对该属性名称的分配

它不会超载分配,descriptor protocol在运行时可以轻松实现,property对象是 data 描述符对象;他们可以截获它们所属的类的实例的所有属性访问(获取,设置和删除),因此可以否决任何这些操作。这与C ++赋值重载不同,后者在编译时(IIRC)处理并在整个实例上运行,而不仅仅是实例上的属性。

真正发生的是,属性分配是由在object.__setattr__ special method中为其实例分配了属性的类对象处理的。该类将检查给定的属性名称是否被类中的对象 覆盖,该对象是使用__set____delete__方法的描述符对象。

因此,可以通过__setattr__特殊方法将 general 属性分配挂钩,Python将属性设置委托给实例的父类型:

# foo.attr = bar   -> Python essentially calls __setattr__ on the class 
type(foo).__setattr__(foo, "attr", bar)

,然后在通常的简单情况下变成

foo.__dict__["attr"] = bar

但实际上,在type(foo)及其父类上搜索了数据描述符 first 。如果存在这样的对象,那么的任务是处理属性设置:

obj = None
for cls in reversed(type(foo).__mro__):
    if "attr" in cls.__dict__:
        obj = cls.__dict__["attr"]
        break
if hasattr(obj, "__set__") or hasattr(obj, "__delete__"):  # data descriptor?
    try:
        obj.__set__(foo, bar)
    except AttributeError:
        raise AttributeError("can't set attribute")
else:
    foo.__dict__["attr"] = bar

property对象实现__set__,此实现将调用您的setter(如果已设置)。