Classes can override __getattr__
to return a default value for missing attributes:
class Example:
def __getattr__(self, attr): # only called when missing
return None
Testing it:
>>> ex = Example()
>>> ex.attr = 1
>>> ex.attr
1
>>> ex.missing # evaluates to `None
>>>
However, this will not allow for chaining:
>>> ex.missing.missing
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'missing'
Nor will it deal with attempts to call methods that are absent:
>>> ex.impossible()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
To fix this, we can make a proxy object:
class GetAnything:
def __getattr__(self, attr):
return self
def __call__(self, *args, **kwargs): # also allow calls to work
return self
def __repr__(self):
return '<Missing value>'
# Reassign the name to avoid making more instances
GetAnything = GetAnything()
And return that instead of None
:
class Example:
def __getattr__(self, attr): # only called when missing
return GetAnything
Now it chains as desired:
>>> Example().missing_attribute.missing_method().whatever
<Missing value>