uniqueeverseen aaaabbbccdaabbb a b c d uniqueeverseen abbccad str lower a b c d copied from moreitertools 8 8 if obj is iterable return an iterator over its items obj 1 2 3 listalwaysiterableobj 1 2 3 if obj is not iterable return a oneitem iterable containing obj obj 1 listalwaysiterableobj 1 if obj is none return an empty iterable obj none listalwaysiterablenone by default binary and text strings are not considered iterable obj foo listalwaysiterableobj foo if basetype is set objects for which isinstanceobj basetype returns true won t be considered iterable obj a 1 listalwaysiterableobj iterate over the dict s keys a listalwaysiterableobj basetypedict treat dicts as a unit a 1 set basetype to none to avoid any special handling and treat objects python considers iterable as iterable obj foo listalwaysiterableobj basetypenone f o o unique_everseen aaaabbbccdaabbb a b c d unique_everseen abbccad str lower a b c d copied from more_itertools 8 8 if obj is iterable return an iterator over its items obj 1 2 3 list always_iterable obj 1 2 3 if obj is not iterable return a one item iterable containing obj obj 1 list always_iterable obj 1 if obj is none return an empty iterable obj none list always_iterable none by default binary and text strings are not considered iterable obj foo list always_iterable obj foo if base_type is set objects for which isinstance obj base_type returns true won t be considered iterable obj a 1 list always_iterable obj iterate over the dict s keys a list always_iterable obj base_type dict treat dicts as a unit a 1 set base_type to none to avoid any special handling and treat objects python considers iterable as iterable obj foo list always_iterable obj base_type none f o o
from itertools import filterfalse


def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    
    
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element



def always_iterable(obj, base_type=(str, bytes)):
    
    if obj is None:
        return iter(())

    if (base_type is not None) and isinstance(obj, base_type):
        return iter((obj,))

    try:
        return iter(obj)
    except TypeError:
        return iter((obj,))