def attr_func(*attrs, **kwargs):
    """Creates an "attribute function" for given attribute name(s).

    Resulting function will retrieve attributes with given names, in order,
    from the object that has been passed to it.
    For example, ``attr_func('a', 'b')(foo)`` yields the same as ``foo.a.b``

    :param attrs: Attribute names
    :param default: Optional keyword argument specifying default value
                    that will be returned when some attribute is not present

    :return: Unary attribute function
    """
    ensure_argcount(attrs, min_=1)
    ensure_keyword_args(kwargs, optional=('default',))

    # preprocess argument list:
    # * allow dots in arguments, interpreting them as multiple attributes,
    #   e.g. ``attr_func('a.b')`` as ``attr_func('a', 'b')``
    # * make sure the attribute names are valid Python identifiers
    attrs = map(ensure_string, attrs)
    attrs = flatten(attr.split('.') if '.' in attr else [attr]
                    for attr in attrs)
    for attr in attrs:
        if not is_identifier(attr):
            raise ValueError("'%s' is not a valid attribute name", attr)

    if 'default' in kwargs:
        default = kwargs['default']
        if len(attrs) == 1:
            getattrs = lambda obj: getattr(obj, attrs[0], default)
        else:
            def getattrs(obj):
                for attr in attrs:
                    try:
                        obj = getattr(obj, attr)
                    except AttributeError:
                        return default
                return obj
    else:
        if len(attrs) == 1:
            getattrs = operator.attrgetter(attrs[0])
        else:
            def getattrs(obj):
                for attr in attrs:
                    obj = getattr(obj, attr)
                return obj

    return getattrs
def attr_func ( * attrs , ** kwargs ) : ensure_argcount ( attrs , min_ = 1 ) ensure_keyword_args ( kwargs , optional = ( 'default' , ) ) attrs = map ( ensure_string , attrs ) attrs = flatten ( attr . split ( '.' ) if '.' in attr else [ attr ] for attr in attrs ) for attr in attrs : if not is_identifier ( attr ) : raise ValueError ( "'%s' is not a valid attribute name" , attr ) if 'default' in kwargs : default = kwargs [ 'default' ] if len ( attrs ) == 1 : getattrs = lambda obj : getattr ( obj , attrs [ 0 ] , default ) else : def getattrs ( obj ) : for attr in attrs : try : obj = getattr ( obj , attr ) except AttributeError : return default return obj else : if len ( attrs ) == 1 : getattrs = operator . attrgetter ( attrs [ 0 ] ) else : def getattrs ( obj ) : for attr in attrs : obj = getattr ( obj , attr ) return obj return getattrs
Creates an "attribute function" for given attribute name(s).

    Resulting function will retrieve attributes with given names, in order,
    from the object that has been passed to it.
    For example, ``attr_func('a', 'b')(foo)`` yields the same as ``foo.a.b``

    :param attrs: Attribute names
    :param default: Optional keyword argument specifying default value
                    that will be returned when some attribute is not present

    :return: Unary attribute function