Python: how to implement __getattr__()?

Question:

My class has a dict, for example:

class MyClass(object):
    def __init__(self):
        self.data = {'a': 'v1', 'b': 'v2'}

Then I want to use the dict’s key with MyClass instance to access the dict, for example:

ob = MyClass()
v = ob.a   # Here I expect ob.a returns 'v1'

I know this should be implemented by __getattr__, but I’m new to Python, I don’t exactly know how to implement it.

Asked By: TieDad

||

Answers:

class MyClass(object):

    def __init__(self):
        self.data = {'a': 'v1', 'b': 'v2'}

    def __getattr__(self, attr):
        return self.data[attr]

>>> ob = MyClass()
>>> v = ob.a
>>> v
'v1'

Be careful when implementing __setattr__ though, you will need to make a few modifications:

class MyClass(object):

    def __init__(self):
        # prevents infinite recursion from self.data = {'a': 'v1', 'b': 'v2'}
        # as now we have __setattr__, which will call __getattr__ when the line
        # self.data[k] tries to access self.data, won't find it in the instance 
        # dictionary and return self.data[k] will in turn call __getattr__
        # for the same reason and so on.... so we manually set data initially
        super(MyClass, self).__setattr__('data', {'a': 'v1', 'b': 'v2'})

    def __setattr__(self, k, v):
        self.data[k] = v

    def __getattr__(self, k):
        # we don't need a special call to super here because getattr is only 
        # called when an attribute is NOT found in the instance's dictionary
        try:
            return self.data[k]
        except KeyError:
            raise AttributeError

>>> ob = MyClass()
>>> ob.c = 1
>>> ob.c
1

If you don’t need to set attributes just use a namedtuple
eg.

>>> from collections import namedtuple
>>> MyClass = namedtuple("MyClass", ["a", "b"])
>>> ob = MyClass(a=1, b=2)
>>> ob.a
1

If you want the default arguments you can just write a wrapper class around it:

class MyClass(namedtuple("MyClass", ["a", "b"])):

    def __new__(cls, a="v1", b="v2"):
        return super(MyClass, cls).__new__(cls, a, b)

or maybe it looks nicer as a function:

def MyClass(a="v1", b="v2", cls=namedtuple("MyClass", ["a", "b"])):
    return cls(a, b)

>>> ob = MyClass()
>>> ob.a
'v1'
Answered By: jamylak
class A(object):
  def __init__(self):
     self.data = {'a': 'v1', 'b': 'v2'}
  def __getattr__(self, attr):
     try:
       return self.data[attr]
     except Exception:
       return "not found"


>>>a = A()
>>>print a.a
v1
>>>print a.c
not found
Answered By: Adem ÖztaƟ

I like to take this therefore.

I took it from somewhere, but I don’t remember where.

class A(dict):
    def __init__(self, *a, **k):
        super(A, self).__init__(*a, **k)
        self.__dict__ = self

This makes the __dict__ of the object the same as itself, so that attribute and item access map to the same dict:

a = A()
a['a'] = 2
a.b = 5
print a.a, a['b'] # prints 2 5
Answered By: glglgl

I figured out an extension to @glglgl’s answer that handles nested dictionaries and dictionaries insides lists that are in the original dictionary:

class d(dict):
    def __init__(self, *a, **k): 
        super(d, self).__init__(*a, **k)
        self.__dict__ = self
        for k in self.__dict__:
            if isinstance(self.__dict__[k], dict):
                self.__dict__[k] = d(self.__dict__[k])
            elif isinstance(self.__dict__[k], list):
                for i in range(len(self.__dict__[k])):
                    if isinstance(self.__dict__[k][i], dict):
                        self.__dict__[k][i] = d(self.__dict__[k][i])
Answered By: Adam Haile

You can initialize your class dictionary through the constructor:

    def __init__(self,**data):

And call it as follows:

f = MyClass(**{'a': 'v1', 'b': 'v2'})

All of the instance attributes being accessed (read) in __setattr__, need to be declared using its parent (super) method, only once:

    super().__setattr__('NewVarName1', InitialValue)

Or

    super().__setattr__('data', dict())

Thereafter, they can be accessed or assigned to in the usual manner:

    self.data = data

And instance attributes not being accessed in __setattr__, can be declared in the usual manner:

    self.x = 1

The overridden __setattr__ method must now call the parent method inside itself, for new variables to be declared:

    super().__setattr__(key,value)

A complete class would look as follows:

class MyClass(object):
    def __init__(self, **data):
        # The variable self.data is used by method __setattr__
        # inside this class, so we will need to declare it 
        # using the parent __setattr__ method:
        super().__setattr__('data', dict())
        self.data = data            
        # These declarations will jump to
        # super().__setattr__('data', dict())
        # inside method __setattr__ of this class:
        self.x = 1
        self.y = 2

    def __getattr__(self, name):
    # This will callback will never be called for instance variables
    # that have beed declared before being accessed.
        if name in self.data:
            # Return a valid dictionary item:
            return self.data[name]
        else:
            # So when an instance variable is being accessed, and
            # it has not been declared before, nor is it contained
            # in dictionary 'data', an attribute exception needs to
            # be raised.
            raise AttributeError

    def __setattr__(self, key, value):
        if key in self.data:
            # Assign valid dictionary items here:
            self.data[key] = value
        else:
            # Assign anything else as an instance attribute:
            super().__setattr__(key,value)

Test:

f = MyClass(**{'a': 'v1', 'b': 'v2'})
print("f.a = ", f.a)
print("f.b = ", f.b)
print("f.data = ", f.data)
f.a = 'c'
f.d = 'e'
print("f.a = ", f.a)
print("f.b = ", f.b)
print("f.data = ", f.data)
print("f.d = ", f.d)
print("f.x = ", f.x)
print("f.y = ", f.y)
# Should raise attributed Error
print("f.g = ", f.g)

Output:

f.a =  v1
f.b =  v2
f.data =  {'a': 'v1', 'b': 'v2'}
f.a =  c
f.b =  v2
f.data =  {'a': 'c', 'b': 'v2'}
f.d =  e
f.x =  1
f.y =  2
Traceback (most recent call last):
  File "MyClass.py", line 49, in <module>
    print("f.g = ", f.g)
  File "MyClass.py", line 25, in __getattr__
    raise AttributeError
AttributeError
Answered By: Tjaart

I think this implement is cooler

class MyClass(object):
    def __init__(self):
        self.data = {'a': 'v1', 'b': 'v2'}
    def __getattr__(self,key):
        return self.data.get(key,None)
Answered By: mxl

Late to the party, but found two really good resources that explain this better (IMHO).

As explained here, you should use self.__dict__ to access fields from within __getattr__, in order to avoid infinite recursion. The example provided is:

def __getattr__(self, attrName):
  if not self.__dict__.has_key(attrName):
     value = self.fetchAttr(attrName)    # computes the value
     self.__dict__[attrName] = value
  return self.__dict__[attrName]

Note: in the second line (above), a more Pythonic way would be (has_key apparently was even removed in Python 3):

if attrName not in self.__dict__:

The other resource explains that the __getattr__ is invoked only when the attribute is not found in the object, and that hasattr always returns True if there is an implementation for __getattr__. It provides the following example, to demonstrate:

class Test(object):
    def __init__(self):
        self.a = 'a'
        self.b = 'b'

    def __getattr__(self, name):
        return 123456

t = Test()
print 'object variables: %r' % t.__dict__.keys()
#=> object variables: ['a', 'b']
print t.a
#=> a
print t.b
#=> b
print t.c
#=> 123456
print getattr(t, 'd')
#=> 123456
print hasattr(t, 'x')
#=> True     
Answered By: marcelocra

A simple approach to solving your __getattr__()/__setattr__() infinite recursion woes

Implementing one or the other of these magic methods can usually be easy. But when overriding them both, it becomes trickier. This post’s examples apply mostly to this more difficult case.

When implementing both these magic methods, it’s not uncommon to get stuck figuring out a strategy to get around recursion in the __init__() constructor of classes. This is because variables need to be initialized for the object, but every attempt to read or write those variables go through __get/set/attr__(), which could have more unset variables in them, incurring more futile recursive calls.

Up front, a key point to remember is that __getattr__() only gets called by the runtime if the attribute can’t be found on the object already. The trouble is to get attributes defined without tripping these functions recursively.

Another point is __setattr__() will get called no matter what. That’s an important distinction between the two functions, which is why implementing both attribute methods can be tricky.

This is one basic pattern that solves the problem.

class AnObjectProxy:
    _initialized = False # *Class* variable 'constant'.

    def __init__(self):
        self._any_var = "Able to access instance vars like usual."
        self._initialized = True # *instance* variable.

    def __getattr__(self, item):
        if self._initialized:
            pass # Provide the caller attributes in whatever ways interest you.
        else:
            try:
                return self.__dict__[item] # Transparent access to instance vars.
            except KeyError:
                raise AttributeError(item)

    def __setattr__(self, key, value):
        if self._initialized:
            pass # Provide caller ways to set attributes in whatever ways.
        else:
            self.__dict__[key] = value # Transparent access.

While the class is initializing and creating it’s instance vars, the code in both attribute functions permits access to the object’s attributes via the __dict__ dictionary transparently – your code in __init__() can create and access instance attributes normally. When the attribute methods are called, they only access self.__dict__ which is already defined, thus avoiding recursive calls.

In the case of self._any_var, once it’s assigned, __get/set/attr__() won’t be called to find it again.

Stripped of extra code, these are the two pieces that are most important.

...     def __getattr__(self, item):
...         try:
...             return self.__dict__[item]
...         except KeyError:
...             raise AttributeError(item)
... 
...     def __setattr__(self, key, value):
...         self.__dict__[key] = value

Solutions can build around these lines accessing the __dict__ dictionary. To implement an object proxy, two modes were implemented: initialization and post-initialization in the code before this – a more detailed example of the same is below.

There are other examples in answers that may have differing levels of effectiveness in dealing with all aspects of recursion. One effective approach is accessing __dict__ directly in __init__() and other places that need early access to instance vars. This works but can be a little verbose. For instance,

self.__dict__['_any_var'] = "Setting..."

would work in __init__().

My posts tend to get a little long-winded.. after this point is just extra. You should already have the idea with the examples above.

A drawback to some other approaches can be seen with debuggers in IDE’s. They can be overzealous in their use of introspection and produce warning and error recovery messages as you’re stepping through code. You can see this happening even with solutions that work fine standalone. When I say all aspects of recursion, this is what I’m talking about.

The examples in this post only use a single class variable to support 2-modes of operation, which is very maintainable.

But please NOTE: the proxy class required two modes of operation to set up and proxy for an internal object. You don’t have to have two modes of operation.

You could simply incorporate the code to access the __dict__ as in these examples in whatever ways suit you.

If your requirements don’t include two modes of operation, you may not need to declare any class variables at all. Just take the basic pattern and customize it.

Here’s a closer to real-world (but by no means complete) example of a 2-mode proxy that follows the pattern:

>>> class AnObjectProxy:
...     _initialized = False  # This class var is important. It is always False.
...                           # The instances will override this with their own, 
...                           # set to True.
...     def __init__(self, obj):
...         # Because __getattr__ and __setattr__ access __dict__, we can
...         # Initialize instance vars without infinite recursion, and 
...         # refer to them normally.
...         self._obj         = obj
...         self._foo         = 123
...         self._bar         = 567
...         
...         # This instance var overrides the class var.
...         self._initialized = True
... 
...     def __setattr__(self, key, value):
...         if self._initialized:
...             setattr(self._obj, key, value) # Proxying call to wrapped obj.
...         else:
...             # this block facilitates setting vars in __init__().
...             self.__dict__[key] = value
... 
...     def __getattr__(self, item):
...         if self._initialized:
...             attr = getattr(self._obj, item) # Proxying.
...             return attr
...         else:
...             try:
...                 # this block facilitates getting vars in __init__().
...                 return self.__dict__[item]
...             except KeyError:
...                 raise AttributeError(item)
... 
...     def __call__(self, *args, **kwargs):
...         return self._obj(*args, **kwargs)
... 
...     def __dir__(self):
...         return dir(self._obj) + list(self.__dict__.keys())

The 2-mode proxy only needs a bit of “bootstrapping” to access vars in its own scope at initialization before any of its vars are set. After initialization, the proxy has no reason to create more vars for itself, so it will fare fine by deferring all attribute calls to it’s wrapped object.

Any attribute the proxy itself owns will still be accessible to itself and other callers since the magic attribute functions only get called if an attribute can’t be found immediately on the object.

Hopefully this approach can be of benefit to anyone who appreciates a direct approach to resolving their __get/set/attr__() __init__() frustrations.

Answered By: Todd
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.