使用__getattr__和getattr的无限循环

时间:2015-05-06 22:17:37

标签: python python-2.7 infinite getattr

好吧,我遇到了一些问题,我不太清楚为什么会出现问题。我想要做的是允许通过snake_case中的snake_case或camelCase访问对象上的属性。我认为__getattr__是正确的方法,但显然我错了,我不是前

所以这是我简化的实现。在这种情况下,无论您访问哪个属性,我都希望返回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的工作方式的误解有关。你们都必须指出的任何建议或文件都会非常有益。提前谢谢。

2 个答案:

答案 0 :(得分:4)

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

仅当您的实例没有该属性时,才会调用

__getattr__;这是一个后备。在hasattr()中使用__getattr__完全没有意义。

由于存在f.x,因此永远不会调用Foo.__getattr__f.y不存在,因此会调用Foo.__getattr__(f, 'y'),调用hasattr(f, 'y')调用调用getattr(f, 'y')的{​​{1}},因为Foo.__getattr__(f, 'y')属性没有&#39} ; t存在等等。

来自object.__getatt__() documentation

  

当属性查找未在通常位置找到该属性时调用(即,它不是实例属性,也不在类树中找到自己)。

来自hasattr() function documentation

  

(这是通过调用y并查看是否引发异常来实现的。)

答案 1 :(得分:0)

我要发布我在开头谈到的我的snake / camelCase问题的工作实现。查看@ 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