Search code examples
pythongetattr

After calling __getattr__ method


In Learning Python 3rd, I saw this code

class wrapper:
    def __init__(self, object):
        self.wrapped = object
    def __getattr__(self, attrname):
        print("Trace:", attrname)
        return getattr(self.wrapped, attrname)

x = wrapper([1,2,3])
x.append(4)
print(x.wrapped)

I want to know exactly what happens after calling this __getattr__ method, which only returns the method by getattr.

Why is the result of the last line [1, 2, 3, 4]?

There is no code that execute the returned function with the original argument.


Solution

  • The wrapper class does not have a .append attribute, so Python falls back to the wrapper.__getattr__ method. From the object.__getattr__ special method 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).

    The wrapped object (the list object with [1, 2, 3]) does have a append attribute (a method), so getattr(self.wrapped, 'append') returns it.

    The returned method is called, passing in 4, appending that to the self.wrapped list object.

    You can easily reproduce the steps yourself:

    >>> wrapped = [1, 2, 3]
    >>> getattr(wrapped, 'append')
    <built-in method append of list object at 0x107256560>
    >>> getattr(wrapped, 'append')(4)
    >>> wrapped
    [1, 2, 3, 4]