def get_iterable_itemtype(obj):
    """Attempts to get an iterable's itemtype without iterating over it,
    not even partly. Note that iterating over an iterable might modify
    its inner state, e.g. if it is an iterator.
    Note that obj is expected to be an iterable, not a typing.Iterable.
    This function leverages various alternative ways to obtain that
    info, e.g. by looking for type annotations of '__iter__' or '__getitem__'.
    It is intended for (unknown) iterables, where the type cannot be obtained
    via sampling without the risk of modifying inner state.
    """
    # support further specific iterables on demand
    try:
        if isinstance(obj, range):
            tpl = tuple(deep_type(obj.start), deep_type(obj.stop), deep_type(obj.step))
            return Union[tpl]
    except TypeError:
        # We're running Python 2
        pass
    if type(obj) is tuple:
        tpl = tuple(deep_type(t) for t in obj)
        return Union[tpl]
    elif type(obj) is types.GeneratorType:
        return get_generator_yield_type(obj)
    else:
        tp = deep_type(obj)
        if is_Generic(tp):
            if issubclass(tp.__origin__, typing.Iterable):
                if len(tp.__args__) == 1:
                    return tp.__args__[0]
                return _select_Generic_superclass_parameters(tp, typing.Iterable)[0]
    if is_iterable(obj):
        if type(obj) is str:
            return str
        if hasattr(obj, '__iter__'):
            if has_type_hints(obj.__iter__):
                itrator = _funcsigtypes(obj.__iter__, True, obj.__class__)[1]
                if is_Generic(itrator) and itrator.__origin__ is typing.Iterator:
                    return itrator.__args__[0]
        if hasattr(obj, '__getitem__'):
            if has_type_hints(obj.__getitem__):
                itrator =  _funcsigtypes(obj.__getitem__, True, obj.__class__)[1]
                if is_Generic(itrator) and itrator.__origin__ is typing.Iterator:
                    return itrator.__args__[0]
        return None # means that type is unknown
    else:
        raise TypeError('Not an iterable: '+str(type(obj)))