__builtin__.iterator does not exist?

夙愿已清 提交于 2019-12-13 17:32:46

问题


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?


回答1:


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).




回答2:


Worse than that, it is a type that is not immediately a class.

>>> type(iter(range(5)))
<type 'listiterator'>

When you ask a (new-style) class instance for its type it says it is a class.

>>> class X(object): pass
...
>>> type(X())
<class '__main__.X'>

(And why would they implement new functionality with an old-style class?)

Given that, if you got a hold of it what would you do with it?

OK, so you can get it, and if you poke around, there is a class in there somewhere

>>> it = iter(range(5)).__class__

But you can't inherit from it

>>> class it2(it): pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    type 'listiterator' is not an acceptable base type

And monkey-patching it seems outright dastardly. I hope something would stop you.

You also can't instantiate it directly:

>>> x = it()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot create 'listiterator' instances

So isn't it better for it to just pretend not to exist, rather than showing up and apologizing for all the normal things it cannot do?

The same goes for things like function, int, double, str, etc. Most of those at least let you instantiate them, but they are not really classes, and so going much farther is spooky.



来源:https://stackoverflow.com/questions/25612946/builtin-iterator-does-not-exist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!