def flatten(x):
    r"""
    
    >>> flatten("hello")
    'hello'
    >>> flatten({"a":[["hi"]]})
    {'a': [['hi']]}
    >>> flatten(None) is None
    True
    >>> flatten(3)
    3
    >>> flatten([0, [1, ["two"]]])
    [0, 1, 'two']
    >>> flatten( (0, (1, ("two",))) )
    (0, 1, 'two')
    >>> flatten([0, [1, 2], 3, ([4, 5], 6)])
    [0, 1, 2, 3, 4, 5, 6]
    >>> flatten( (0, 1, (i + 1 for i in xrange(1, 3)) ) )
    (0, 1, 2, 3)
    >>> flatten([[[[[0]]]]])
    [0]
    >>> flatten([0, [[{"a":[["hi"]]}]]])
    [0, {'a': [['hi']]}]
    
    """
    
    if isinstance(x, basestring):
        return x
    if hasattr(x, "__iter__"):
        if hasattr(x, "items"):
            return x
    else:
        return x
    
    is_tuple = isinstance(x, tuple)
    
    # leave exception here unhandled
    # if conversion to list fails
    x = list(x)
    x.reverse()
    
    r = []
    while x:
        y = x.pop(-1)
        if isinstance(y, basestring):
            r.append(y)
            continue
        if hasattr(y, "__iter__"):
            if hasattr(y, "items"):
                r.append(y)
                continue
        else:
            r.append(y)
            continue
        # leave exception here unhandled
        # if conversion to list fails
        y = list(y)
        y.reverse()
        x.extend(y)
        
    if is_tuple:
        return tuple(r)
    else:
        return r

    
    >>> flatten("hello")
    'hello'
    >>> flatten({"a":[["hi"]]})
    {'a': [['hi']]}
    >>> flatten(None) is None
    True
    >>> flatten(3)
    3
    >>> flatten([0, [1, ["two"]]])
    [0, 1, 'two']
    >>> flatten( (0, (1, ("two",))) )
    (0, 1, 'two')
    >>> flatten([0, [1, 2], 3, ([4, 5], 6)])
    [0, 1, 2, 3, 4, 5, 6]
    >>> flatten( (0, 1, (i + 1 for i in xrange(1, 3)) ) )
    (0, 1, 2, 3)
    >>> flatten([[[[[0]]]]])
    [0]
    >>> flatten([0, [[{"a":[["hi"]]}]]])
    [0, {'a': [['hi']]}]
    
    
recipes/Python/577387_Nonrecursive_Flatten_leaves_Strings_Dicts_alone_/recipe-577387.py