简体   繁体   中英

Infinite loop using __getattr__ and getattr

Okay, I'm having a bit of a problem and I'm not quite sure why its occurring the way that it is. What I'm trying to do is allow access to attributes on an object via snake_case or camelCase in python 2.7.XI thought that __getattr__ was the correct way to do this, but clearly I'm mistaken and I'm not ex

So here's my simplified implementation. In this scenario, no matter what attribute you access, I want foo.x to be returned.

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

Now if I do:

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

However, I don't understand why:

f.y

Loops forever. Interestingly, when I put print "__getattr__ called with : %s" % name at the first line of the __getattr__ , it appears that when fy gets called, the getattr(self, 'x') line does actually get called, but then it doesn't look like getattr is ever actually called with 'x' instead, __getattr__ still says that it is getting called with "y."

I've been looking around, and I think it has something to do with my misunderstanding of how the getattr works. Any advice or documentation that you all have to point me to would be very beneficial. Thanks in advance.

hasattr() is implemented as a call to getattr() and returns False if an exception was raised.

__getattr__ is only called if your instance doesn't have the attribute; it is a fallback. Using hasattr() in __getattr__ is entirely pointless.

Since fx exists, Foo.__getattr__ is never called. fy does not exist, so Foo.__getattr__(f, 'y') is called, which calls hasattr(f, 'y') which calls getattr(f, 'y') which calls Foo.__getattr__(f, 'y') because the y attribute doesn't exist, etc.

From the object.__getatt__() documentation :

Called when an attribute lookup has not found the attribute in the usual places (ie it is not an instance attribute nor is it found in the class tree for self).

and from the hasattr() function documentation :

(This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.)

I'm going to post a working implementation of my snake/camelCase problem that I spoke of at the beginning. Check out @Martijn's answer for an explanation as to why this works and the old one fails.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM