Python: Declaring Dynamic Attributes
The examples below are in Python 3.5, but otherwise this post is applicable to both Python 2.x and 3.x
It is a common solution in Python to override the __getattr__
magic method in classes, to implement dynamic attributes. Consider AttrDict
- it is a dictionary that allows attribute-like access to its stored key-value pairs:
This simplified AttrDict
allows to read dictionary values from it like attributes, but it’s pretty simple to also allow to set key-value pairs. At any rate, here it is in action:
Overriding __getattr__
(and __setattr__
) is very useful - from simple “gimmicks” like AttrDict
that makes your code more readable to essential building blocks of your application like remote procedure callers (RPCs). There is, however, something a little bit frustrating about dynamic attributes - you can’t see them before you use them!
Dynamic attributes have two usability problems when working in an interactive shell. The first is that they don’t appear when a user tries to examine the object’s API by calling the dir
method:
The second problem is autocompletion - if we set normal_attribute
as an attribute the old fashioned way, we get autocompletion from most modern shell environments1:
But setting dynamic_attribute
by inserting it as a dictionary key-value pair does not provide us with autocompletion:
There is, however, an extra step you can take when implementing dynamic attributes which will make it a delight for your users and kill two birds with one stone - implement the __dir__
method. From the docs:
If the object has a method named
__dir__()
, this method will be called and must return the list of attributes. This allows objects that implement a custom__getattr__()
or__getattribute__()
function to customize the waydir()
reports their attributes.
Implementing __dir__
is straightforward: return a list of attribute names for the object:
This will make dir(attrd)
return dynamic attributes as well as the regular ones. The interesting thing about this is that shell environments often use __dir__
to suggest autocompletion options! so without any additional effort, we also get autocompletion2:
Follow me on Twitter and Facebook
Thanks to Ram Rachum for reading drafts of this.