【问题标题】:Infinite loop using __getattr__ and getattr使用 __getattr__ 和 getattr 的无限循环
【发布时间】:2015-07-17 07:01:12
【问题描述】:

好的,我遇到了一点问题,我不太确定为什么会这样。我想要做的是允许通过 python 2.7.XI 中的 snake_case 或 camelCase 访问对象上的属性认为__getattr__ 是这样做的正确方法,但显然我错了,我不是 ex

这是我的简化实现。在这种情况下,无论您访问什么属性,我都希望返回 foo.x

class Foo(object):
  def __init__(self, x):
    self.x = x

  def __getattr__(self, name):
    if hasattr(self, name):
      return getattr(self, name)
    elif hasattr(self, 'x'):
      return getattr(self, 'x')
    else:
      raise AttributeError, n

现在如果我这样做:

f = Foo('myX')
f.x             
# => "myX"

但是,我不明白为什么:

f.y

永远循环。有趣的是,当我将print "__getattr__ called with : %s" % name 放在__getattr__ 的第一行时,似乎当f.y 被调用时,getattr(self, 'x') 行确实被调用了,但是看起来 getattr 并没有真正被调用用“x”调用,__getattr__ 仍然说它被用“y”调用。

我一直在环顾四周,我认为这与我对getattr 工作原理的误解有关。你们都必须向我指出的任何建议或文件都会非常有益。提前致谢。

【问题讨论】:

  • getattr(self, 'x') 完全等同于self.x - 它不会直接进入默认属性查找机制或做任何与self.x 不同的事情。你可能误解了hasattrgetattr 的作用。

标签: python python-2.7 infinite getattr


【解决方案1】:

hasattr() 被实现为对getattr() 的调用,如果引发异常则返回False

__getattr__ 仅在您的实例没有该属性时才被调用;这是一个后备。在__getattr__ 中使用hasattr() 完全没有意义。

由于f.x 存在,Foo.__getattr__ 永远不会被调用。 f.y 不存在,所以调用Foo.__getattr__(f, 'y'),它调用hasattr(f, 'y'),它调用getattr(f, 'y'),它调用Foo.__getattr__(f, 'y'),因为y 属性不存在,等等。

来自object.__getatt__() documentation

当属性查找在通常的地方没有找到该属性时调用(即它不是实例属性,也不是在 self 的类树中找到)。

来自hasattr() function documentation

(这是通过调用getattr(object, name) 并查看它是否引发异常来实现的。)

【讨论】:

  • 非常感谢您的回复。现在这是有道理的。有趣的是 hasattr 是这样实现的,但我认为这是有道理的。我会接受你的回答,我将编写一个可以在下面工作的实现。谢谢!
【解决方案2】:

我将发布我在开头谈到的蛇/骆驼问题的工作实现。查看@Martijn 的答案,了解为什么它有效而旧的失败。

class Foo(object):

def __init__(self, x):
  self.x = x

def __getattr__(self, name):
  #if hasattr(self, name)     # As Martijn pointed out, this call is completely
  #  getattr(self, name)      # useless in this context because the only reason
                              # you are even in __getattr__ is because self
                              # does not have the attribute. This call is what
                              # was causing the infinite loop.
  components = name.split('_')
  camel_case = components[0] + "".join(x.title() for x in components[1:])
  if hasattr(self, camel_case):
    return getattr(self, camel_case)
  else:
    raise AttributeError, name

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多