Dot notation (obj.x.y.z) for nested objects and dictionaries in Python

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