It is possible to control the way attributes are obtained from objects by means of the __getattr__ magic method. When we call something like <myobject>.<myattribute>, Python will look for <myattribute> in the dictionary of the object, calling __getattribute__ on it. If this is not found (namely, the object does not have the attribute we are looking for), then the extra method, __getattr__, is called, passing the name of the attribute (myattribute) as a parameter. By receiving this value, we can control the way things should be returned to our objects. We can even create new attributes, and so on.
In the following listing, the __getattr__ method is demonstrated:
class DynamicAttributes:
def __init__(self, attribute):
self.attribute = attribute
def __getattr__(self, attr):
if attr.startswith("fallback_"...