Simple implementations of nested_getattr(obj, attr, default)
, nested_setattr(obj, attr, val)
and nested_dict_get(dictionary, dotted_key)
.
Nested Object
import functools
raise_attribute_error = object()
def nested_getattr(obj, attr, default=raise_attribute_error):
try:
return functools.reduce(getattr, attr.split('.'), obj)
except AttributeError:
if default != raise_attribute_error:
return default
raise
# only support setting an attribute on an existed nested attribute
def nested_setattr(obj, attr, val):
pre, _, post = attr.rpartition('.')
return setattr(nested_getattr(obj, pre) if pre else obj, post, val)
nested_getattr(user, 'settings.enable_nsfw', None)
nested_setattr(user, 'settings.enable_nsfw', True) # work
nested_setattr(user, 'nonexistent_field.whatever_field', True) # raise AttributeError
ref:
https://stackoverflow.com/questions/11975781/why-does-getattr-not-support-consecutive-attribute-retrievals
https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects
Nested Dictionary
import functools
def nested_dict_get(dictionary, dotted_key):
keys = dotted_key.split('.')
return functools.reduce(lambda d, key: d.get(key) if d else None, keys, dictionary)
user_dict = {
'id': 123,
'username': 'vinta',
'settings': {
'enable_nsfw': True,
},
}
nested_dict_get(user_dict, 'username') # return 'vinta'
nested_dict_get(user_dict, 'settings.enable_nsfw') # return True
nested_dict_get(user_dict, 'settings.notification.new_follower') # return None
ref:
https://stackoverflow.com/questions/25833613/python-safe-method-to-get-value-of-nested-dictionary