使用iter()
,我可以这样做:
>>> listWalker = iter ( [23, 47, 'hike'] )
>>> for x in listWalker: print x,
但我还是可以这样做:
>>> listWalker = [23, 47, 'hike']
>>> for x in listWalker: print x,
它增加了什么价值?
答案 0 :(得分:5)
除了使用iter
显式获取实现__iter__
方法的对象的迭代器之外,还有一个鲜为人知的双参数形式iter
,这使得重复调用函数的迭代器,直到它返回给定的sentinel值。
for line in iter(f.readline, 'EOF'):
print line
前面的代码会调用f.read
(例如,打开文件句柄f
),直到它读取由字符串EOF
组成的行。它与写作大致相同
for line in f:
if line == "EOF":
break
print line
此外,迭代器可能是与迭代的对象不同的对象。这适用于list
类型。这意味着您可以创建两个迭代器,这两个迭代器都在同一个对象上独立地迭代。
itr1 = iter(mylist)
itr2 = iter(mylist)
x = next(itr1) # First item of mylist
y = next(itr1) # Second item of my list
z = next(itr2) # First item of mylist, not the third
然而,文件句柄充当它们自己的迭代器:
>>> f = open('.bashrc')
>>> id(f)
4454569712
>>> id(iter(f))
4454569712
通常,iter
返回的对象取决于对象类型实现的__iter__
方法。
答案 1 :(得分:4)
iter
的要点是它允许你从一个可迭代的对象中获取迭代器并自己使用它,要么实现你自己的for
循环变体,要么保持状态为跨多个循环的迭代。一个简单的例子:
it = iter(['HEADER', 0, 1, 2, 3]) # coming from CSV or such
title = it.next()
for item in it:
# process item
...
此分组习惯用法提供了iter
的更高级用法:
def in_groups(iterable, n):
"""Yield element from iterables grouped in tuples of size n."""
it = iter(iterable)
iters = [it] * n
return zip(*iters)
答案 2 :(得分:0)
当您对变量执行for
循环时,它会隐式调用您实际传递的迭代的__iter__
方法。
当你循环遍历列表,元组和每个可迭代时,你总是使用iter()
。
我认为这个字节码的提取可以说服你:
>>> def a():
... for x in [1,2,3]:
... print x
...
>>> import dis
>>> dis.dis(a)
2 0 SETUP_LOOP 28 (to 31)
3 LOAD_CONST 1 (1)
6 LOAD_CONST 2 (2)
9 LOAD_CONST 3 (3)
12 BUILD_LIST 3
15 GET_ITER # <--- get iter is important here
>> 16 FOR_ITER 11 (to 30)
19 STORE_FAST 0 (x)
3 22 LOAD_FAST 0 (x)
25 PRINT_ITEM
26 PRINT_NEWLINE
27 JUMP_ABSOLUTE 16
>> 30 POP_BLOCK
>> 31 LOAD_CONST 0 (None)
34 RETURN_VALUE
<小时/> 但是,iterables还允许您在Python中使用其他一些东西,例如使用
next()
来进入迭代,或者提升StopIteration
exception。如果您正在处理不同的对象类型并且想要应用通用算法,那么它将非常有用。
答案 3 :(得分:0)
来自the docs:
iter(o [,sentinel])
[...]没有第二个参数,o必须是一个支持。的集合对象 迭代协议(
__iter__()
方法),或者它必须支持 序列协议(带有整数参数的__getitem__()
方法 从0开始)。如果它不支持这些协议中的任何一个, 引发TypeError。 [...]
所以它从一个对象构造一个迭代器。
正如你所说,这是在循环和理解中自动完成的,但有时候你想得到一个迭代器并直接处理它。只要你需要它就可以把它放在心里。
使用第二个参数时:
如果给出第二个参数 sentinel ,则o必须是可调用对象。 在这种情况下创建的迭代器将调用o,每次调用都没有参数 到它的next()方法;如果返回的值等于sentinel, 将引发StopIteration,否则将返回该值。
这对许多事情都很有用,但对于像file.read(bufsize)
这样的遗留风格函数尤其如此,在返回""
之前必须重复调用它。可以使用iter(lambda : file.read(bufsize), "")
将其转换为迭代器。很干净!