使用 __getattr__ 和 getattr 的无限循环
Infinite loop using __getattr__ and getattr
好的,我遇到了一点问题,我不太确定为什么会这样。我想做的是允许通过 snake_case 或 python 中的驼峰命名法访问对象的属性 2.7.X 我认为 __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
的工作原理的误解有关。你们都必须向我指出的任何建议或文档都会非常有益。提前致谢。
hasattr()
实现为对 getattr()
和 returns 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:
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self).
并且来自 hasattr()
function documentation:
(This is implemented by calling getattr(object, name)
and seeing whether it raises an exception or not.)
我将 post 解决我在开头提到的 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
好的,我遇到了一点问题,我不太确定为什么会这样。我想做的是允许通过 snake_case 或 python 中的驼峰命名法访问对象的属性 2.7.X 我认为 __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
的工作原理的误解有关。你们都必须向我指出的任何建议或文档都会非常有益。提前致谢。
hasattr()
实现为对 getattr()
和 returns 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:
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self).
并且来自 hasattr()
function documentation:
(This is implemented by calling
getattr(object, name)
and seeing whether it raises an exception or not.)
我将 post 解决我在开头提到的 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