__getattr __()的无限递归-但是为什么它甚至被调用一次?

pau*_*l23 3 python recursion private-members getattr

好吧,我有一个包含(相关部分)的课程:

class satellite(object):
    def __init__(self, orbit, payload=None, structural_mass=0, structural_price=0):
        self.__all_parts = []
        self.orbit = orbit
        self.payload = payload
        self.structural_mass = structural_mass
        self.structural_price = structural_price

    def __getattr__(self, item):
        found = False
        v = 0
        for i in self.__all_parts:
            t = getattr(i, item, None)
            if t is not None:
                v += t
                found = True
        if found:
            return v
        else:
            raise AttributeError(item)
Run Code Online (Sandbox Code Playgroud)

基本上,我希望做的是将所有(部分)属性从“部分”传播到卫星中。即,如果我有10个零件的质量,卫星的质量就是这些零件的总和。-如果再添加一个具有储能功能的零件-我可以立即向上查找。-如果没有部件具有该属性,则该属性被认为是“不良” /“不存在”,并且会引发正常错误。

现在可以了,除了我这样做时:

s = satellite(None) #most simplistic one
ss = copy.copy(s) 
Run Code Online (Sandbox Code Playgroud)

整个过程都出错了,从而在中给出了无限递归深度错误__getattr__()

现在检查(pycharm的调试器)向我展示了它不断使用as参数迭代getattr:

item = _satellite__all_parts 然后在该行开始下一次迭代 for i in self.__all_parts:

现在,我对此感到震惊:__getattr_()据我所知,为什么__getattr__只对不存在的属性调用此行?-但是self.__all_parts显然__init__是在对象事件中声明的,那么为什么__getattr__还要激活?而且:为什么它不再理解对象了?

当然:我该如何进行这项工作?

编辑:只是为了清楚起见-这仅是由于复制而发生,并且(是由于martijn所致)是特定于复制行为的。链接的问题不处理复制案例。

Mar*_*ers 5

copy.copy()尝试__setstate__实例上访问该属性,但尚未设置任何属性,因为__init__尚未调用(并且不会;copy.copy()将负责在其上设置新属性)。

寻找的__setstate__方法 copy.copy()是可选的,并且您的类确实没有这样的属性。因为它缺少,__getattr__被调用它,因为没有__all_parts属性又或者,该for i in self.__all_parts:行结束调用__getattr__一次。一遍又一遍。

诀窍是通过对其进行测试来尽早消除此循环。最好的方法是对所有以下划线开头的属性进行特殊处理:

if item.startswith('_'):
    # bail out early
    raise AttributeError(item)
Run Code Online (Sandbox Code Playgroud)