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:
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:
__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
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:
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
__getattribute__()function to customize the way
dir()reports their attributes.
__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.