Write a function ```unpack()``` that unpacks a ```list``` of elements that can contain objects(`int`, `str`, `list`, `tuple`, `dict`, `set`) within each other without any predefined depth, meaning that there can be many levels of elements contained in one another.

Example:

```python
unpack([None, [1, ({2, 3}, {'foo': 'bar'})]]) == [None, 1, 2, 3, 'foo', 'bar']
```

Note: you don't have to bother about the order of the elements, especially when unpacking a `dict` or a `set`. Just unpack all the elements.

Difficulty: introductory

Starter code:

def unpack(l):
	

Solutions:
from collections import Iterable

def unpack(iterable):
    lst = []
    for x in iterable:
        if   isinstance(x,dict):     x = unpack(x.items())
        elif isinstance(x,str):      x = [x]
        elif isinstance(x,Iterable): x = unpack(x)
        else:                        x = [x]
        lst.extend(x)
    return lst

def unpack(l):
    """Unpack a list of elements that contains unpackable objects.

    >>> unpack([None, [1, ({2, 3}, {'foo': 'bar'})]])
    [None, 1, 2, 3, 'foo', 'bar']

    """
    res = []
    for i in l:
        if type(i) is list:
            res += unpack(i)
        elif type(i) is tuple:
            res += unpack(list(i))
        elif type(i) is dict:
            res += unpack(list(i.keys()))
            res += unpack(list(i.values()))
        elif type(i) is set:
            res += unpack(list(i))
        else:
            res += [i]
    return res


def unpack(l):
    pac = []
    for e in l:
        if type(e) not in [tuple, list, set, dict]:
            pac.append(e)
        elif type(e) == dict:
            pac += unpack(list(e.items()))
        else:
            pac += unpack(e)
    return pac

def iter_unpack(x):
    if isinstance(x, (tuple, list, set)):
        for item in x:
            yield from iter_unpack(item)
    elif isinstance(x, dict):
        for key, value in x.items():
            yield from iter_unpack(key)
            yield from iter_unpack(value)
    else:
        yield x

def unpack(x):
    return list(iter_unpack(x))

def unpack(L):
    res = []
    for el in L:
        if isinstance(el, (list, tuple, set)):
            res.extend(unpack(el))
        elif isinstance(el, dict):
            res.extend(unpack(el.items()))
        else:
            res.append(el)
    return res

def unpack(li,s=None):
    if s is None : s = []
    for i in li:
        if type(i) in [list, tuple, set] : unpack(i,s)
        elif type(i) == dict : unpack(sum([[k, l] for k, l in i.items()], []),s)
        else : s.append(i)
    return s

from collections import Iterable

def unpack(xs):
    queue = xs[:]
    output = []
    
    while queue:
        x = queue.pop(0)
        
        if type(x) is dict:
            queue.append(x.items())
        elif type(x) != str and isinstance(x, Iterable):
            queue.extend(x)
        else:
            output.append(x)
                
    return output

from collections import Iterable

def unpack(l):
    output = []
    
    queue = l[:]
    while queue:
        x = queue.pop(0)
        
        if type(x) is dict:
            queue.append(x.items())
        elif isinstance(x, Iterable) and type(x) != str:
            for y in x:
                queue.append(y)
        else:
            output.append(x)
                
    return output

def unpack(nested):
    if type(nested) in (tuple, list, set):
        return [flat for value in nested for flat in unpack(value)]
    if type(nested) is dict:
        return [flat for key, value in list(nested.items()) for flat in unpack(key) + unpack(value)]
    return [nested]


from collections import Iterable

def unpack(l):    
    return [l] if not isinstance(l, Iterable) or type(l) == str else unpack(l.items()) if type(l) == dict else [e for a in [unpack(e) for e in l] for e in a]