Search code examples
pythonpython-2.7cpython

__builtin__.iterator does not exist?


Consider:

Python 2.7.3 (default, Aug  2 2012, 16:55:39) 
[GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import __builtin__
>>> type(iter('123'))
<type 'iterator'>
>>> type(iter('123')).__class__
<type 'type'>
>>> type(iter('123')).__name__
'iterator'
>>> type(iter('123')).__module__
'__builtin__'
>>> __builtin__.iterator
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'iterator'
>>> dir(__builtin__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
>>> 

Is it expected that __builtin__.iterator doesn't really exist? Is there an appropriate way to obtain a reference to that class without creating a nonce-instance with iter?


Solution

  • Not all internal object types are listed in the __builtin__ structure, no.

    You won't find the method type there either, nor the generator type, or many others. Only names that you'd actually use in your Python code are listed in that namespace.

    Some such types are listed in the types module, but the iterator type isn't, because, as the source states:

    # Iterators in Python aren't a matter of type but of protocol.  A large
    # and changing number of builtin types implement *some* flavor of
    # iterator.  Don't check the type!  Use hasattr to check for both
    # "__iter__" and "next" attributes instead.
    

    If you wanted to test if something is an iterator, use the Iterator ABC instead:

    import collections
    
    if isinstance(something, collections.Iterator):
    

    If you have some obscure need to get the iterator type as returned for strings, you can use type() on it:

    >>> type(iter('123'))
    <type 'iterator'>
    

    and store that; that's how the types module produces many of its references.

    However, know that that type is not universal:

    >>> iterator = type(iter(''))
    >>> isinstance(iter([]), iterator)
    False
    >>> iter([])
    <listiterator object at 0x108e72d50>
    >>> isinstance(reversed([]), iterator)
    False
    >>> reversed([])
    <listreverseiterator object at 0x108e72d50>
    

    yet testing with the ABC does recognise them all:

    >>> from collections import Iterator
    >>> isinstance(iter([]), Iterator)
    True
    >>> isinstance(iter(reversed([])), Iterator)
    True
    >>> isinstance(iter(''), Iterator)
    True
    

    If you need to create an iterator, then either produce a sequence and return the result of iter() on that, or produce an iterator type yourself. The latter is easy enough, either use a generator expression, use a generator function for __iter__ or give your type a __next__ method that produces an item each time it is called (and have __iter__ return self).