import re
import functools


def rgetattr(obj, attr, *args):
    """
    Recursively get an attribute. This is useful for nested subobjects or chained properties.

    Examples:
        class A(object):
            def __init__(self, a=0):
                self.a = a

        class B(object):
            def __init__(self, b):
                self.b = b

        obj = B(b=A())
        rgetattr(obj, 'b.a')  # this will access obj.b.a and thus print 0

    References:
        - https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-subobjects-chained-properties
    """
    def _getattr(obj, attr):
        search = re.search("\[.*\]", attr)  # check for square brackets
        if search is not None:
            begin_idx, last_idx = search.span()
            a = getattr(obj, attr[:begin_idx], *args)
            idx = last_idx
            while idx != begin_idx:
                idx = attr.find(']', begin_idx)
                s = attr[begin_idx+1:idx]
                if re.match("[0-9]+", s):  # check if numeric string
                    if ':' in s:  # check for ':', i.e. slice
                        sl = slice(*[{True: lambda n: None, False: int}[x == ''](x)
                                     for x in (s.split(':') + ['', '', ''])[:3]])
                        a = a[sl]
                    else:  # if no slice
                        a = a[int(s)]
                else:  # string for dictionary
                    a = a[s]
                begin_idx = idx
            return a
        return getattr(obj, attr, *args)
    return functools.reduce(_getattr, [obj] + attr.split('.'))