重载__setattr__导致AttributeError

时间:2015-11-17 22:39:33

标签: python python-3.x

我有一个存储变量的类,然后应该调用能够执行给定的代码片段,作为参数传递,只要该变量更改为指定的值。我想这样做:

class SharedAttribute(object):    
    def __init__(self, value, onEquals={}):
        self.value = value
        self.onEquals = onEquals

    def __setattr__(self, key, val):
        super(SharedAttribute, self).__setattr__(key, val)  #Set the attribute to the new value

        if key == "value":  #If the attribute being changed is the value attribute:
            if val in self.onEquals:  #If the new value is something that should cause something to happen:
                if type(self.onEquals[val]) == str:  #If there's only one command:
                    exec(self.onEquals[val])  #execute it

                elif type(self.onEquals[val]) == tuple:  #If there's a tuple of commands:
                    for eachFunction in self.onEquals[value]:  #Execute each of them
                        exec(eachFunction)

它会像这样实例化:

foo = SharedAttribute(0, onEquals = {1: 'doSomething(arguments)', 2: ('doAnotherThing()', 'yetAnotherThing(arguments)'})

当我尝试创建一个类的实例时,它给了我

AttributeError: 'SharedAttribute' object has no attribute 'onEquals'.

我认为这是因为if val in self.onEquals在定义onEquals时尝试访问onEquals,因为它正在调用__setattr__来定义它,但我添加了if key == "value":,它仍在表现。怎么了?

2 个答案:

答案 0 :(得分:1)

您的问题是__setattr__中的self.value = value也被__init__调用,然后访问尚未定义的self.onEquals

您可以按照建议尝试更改self.valueself.onEquals__init__行的顺序。

但是,如果您不希望在实例化类时从onEquals运行函数,请保持订单不变,并检查onEquals是否已在__setattr__中设置:

def __setattr__(self, key, val):
    super(SharedAttribute, self).__setattr__(key, val)

    if key == "value" and getattr(self, "onEquals", False):
        ...

答案 1 :(得分:0)

__setattr__调用每次访问权限以保存属性。当SharedAttribute的{​​{1}}运行时,__init__()self.value都不存在,但self.onEquals会在设置时__setattr__尝试访问self.onEquals self.value 1}} - 因为您先设置self.value

所以你有几种不同的方法可以解决这个问题:

  • 交换__init__功能中的两行,或
  • 将虚拟类变量onEquals设置为空dict

第一种解决方案是最快捷,最简单的解决方案;第二种解决方案存在一些风险,即您将无意中访问onEquals的类版本,然后很难找到错误来解决问题。