只要有一个论点,iter
必须给出一个具有以下特征的对象__iter__
特殊方法,or __getitem__
特殊方法。如果它们都不存在,iter
will提出错误
>>> iter(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not iterable
有 2 个迭代协议。旧协议依赖于调用__getitem__
对于从 0 到 1 的连续整数IndexError
。新协议依赖于从返回的迭代器__iter__
.
在Python 2中,str
甚至没有__iter__
特殊方法:
Python 2.7.12+ (default, Sep 17 2016, 12:08:02)
[GCC 6.2.0 20160914] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'abc'.__iter__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__iter__'
但它仍然是可迭代的:
>>> iter('abc')
<iterator object at 0x7fcee9e89390>
为了使您的自定义类可迭代,您需要either __iter__
or __getitem__
这引发了IndexError
对于不存在的项目:
class Foo:
def __iter__(self):
return iter(range(5))
class Bar:
def __getitem__(self, i):
if i >= 5:
raise IndexError
return i
使用这些:
>>> list(iter(Foo()))
[0, 1, 2, 3, 4]
>>> list(iter(Bar()))
[0, 1, 2, 3, 4]
通常是明确的iter
不需要,因为for
期望的循环和方法可迭代对象将隐式创建一个迭代器:
>>> list(Foo())
[0, 1, 2, 3, 4]
>>> for i in Bar():
0
1
2
3
4
对于 2 参数形式,第一个参数必须是实现__call__
。第一个参数在没有参数的情况下被调用;返回值是从迭代器产生的。当该迭代中函数调用返回的值等于给定值时,迭代停止sentinel值,就好像:
value = func()
if value == sentinel:
return
else:
yield value
例如,获取骰子上的值before我们扔 6 个,
>>> import random
>>> throw = lambda: random.randint(1, 6)
>>> list(iter(throw, 6))
[3, 2, 4, 5, 5]
>>> list(iter(throw, 6))
[1, 3, 1, 3, 5, 1, 4]
为了进一步澄清,给定的函数(或给定的对象)__call__
特殊方法)在每次调用时不带参数next()
用在迭代器上:
>>> def throw_die():
... die = random.randint(1, 6)
... print("returning {}".format(die))
... return die
...
>>> throws = iter(throw_die, 6)
>>> next(throws)
returning 2
2
>>> next(throws)
returning 4
4
>>> next(throws)
returning 6
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
(i.e. throw
被称为throw()
如果返回值不等于 6,则返回)。
或者在以下情况下
>>> fin_1byte = iter(functools.partial(fin.read, 1), '')
>>> for c in fin_1byte:
... print c,
从文件末尾读取文件返回空字符串(如果是二进制文件,则为空字节):
>>> from io import StringIO
>>> fin = StringIO(u'ab')
>>> fin.read(1)
u'a'
>>> fin.read(1)
u'b'
>>> fin.read(1)
u''
如果尚未到达文件末尾,则返回一个字符。
这也可用于通过重复的函数调用创建无限迭代器:
>>> dice = iter(throw, 7)
由于返回的值永远不可能等于 7,因此迭代器将永远运行。一个常见的习惯用法是使用匿名object
确保对于任何可以想象的值,比较都不会成功
>>> dice = iter(throw, object())
Because
>>> object() != object()
True
注意,这个词sentinel通常用于在某些数据中用作结束标记的值,并且该值不会在数据中自然出现,如这个Java答案 https://stackoverflow.com/questions/21666508/can-someone-explain-to-me-what-a-sentinel-does-in-java-or-how-it-works.