def row2dict(row, depth=None, exclude=None, exclude_pk=None,
             exclude_underscore=None, only=None, fk_suffix=None):
    if depth == 0:
        return None
    d, mapper = {}, get_mapper(row)
    if depth is None:
        depth = getattr(row, ATTR_DEPTH, DEFAULT_DEPTH) - 1
    else:
        depth -= 1
    if exclude is None:
        exclude = getattr(row, ATTR_EXCLUDE, DEFAULT_EXCLUDE)
    if exclude_pk is None:
        exclude_pk = getattr(row, ATTR_EXCLUDE_PK, DEFAULT_EXCLUDE_PK)
    if exclude_underscore is None:
        exclude_underscore = getattr(row, ATTR_EXCLUDE_UNDERSCORE,
                                     DEFAULT_EXCLUDE_UNDERSCORE)
    if only is None:
        only = getattr(row, ATTR_ONLY, DEFAULT_ONLY)
    if fk_suffix is None:
        fk_suffix = getattr(row, ATTR_FK_SUFFIX, DEFAULT_FK_SUFFIX)
    for c in mapper.columns.keys() + mapper.synonyms.keys():
        if c in exclude or \
                check_exclude_pk(c, exclude_pk, fk_suffix=fk_suffix) or \
                check_exclude_underscore(c, exclude_underscore) or \
                check_only(c, only):
            continue
        d[c] = getattr(row, c)
    for r in mapper.relationships.keys():
        if r in exclude or check_only(r, only):
            continue
        attr = getattr(row, r)
        backref = get_backref(mapper.relationships[r])
        if backref:
            exclude.add(backref)
        kwargs = dict(depth=depth, exclude=exclude, exclude_pk=exclude_pk,
                      exclude_underscore=exclude_underscore, only=only,
                      fk_suffix=fk_suffix)
        if isinstance(attr, collections.InstrumentedList):
            d[r] = [row2dict(i, **kwargs) for i in attr if depth]
        else:
            d[r] = row2dict(attr, **kwargs)
    return d