Python 中 iter 函数的第二个参数是什么?
What is the 2nd argument for the iter function in Python?
让我们考虑一个文件:
$ echo -e """This is a foo bar sentence .\nAnd this is the first txtfile in the corpus .""" > test.txt
$ cat test.txt
This is a foo bar sentence .
And this is the first txtfile in the corpus .
当我想按字符读取文件时,我可以这样做 :
>>> fin = open('test.txt')
>>> while fin.read(1):
... fin.seek(-1,1)
... print fin.read(1),
...
T h i s i s a f o o b a r s e n t e n c e .
A n d t h i s i s t h e f i r s t t x t f i l e i n t h e c o r p u s .
但是使用 while 循环可能看起来有点不符合 Python 风格,尤其是。当我使用 fin.read(1)
检查 EOF 然后回溯以读取当前字节时。所以我可以做这样的事情 How to read a single character at a time from a file in Python?:
>>> import functools
>>> fin = open('test.txt')
>>> fin_1byte = iter(functools.partial(fin.read, 1), '')
>>> for c in fin_1byte:
... print c,
...
T h i s i s a f o o b a r s e n t e n c e .
A n d t h i s i s t h e f i r s t t x t f i l e i n t h e c o r p u s .
但是当我在没有第二个参数的情况下尝试它时,它会抛出一个 TypeError
:
>>> fin = open('test.txt')
>>> fin_1byte = functools.partial(fin.read, 1)
>>> for c in iter(fin_1byte):
... print c,
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'functools.partial' object is not iterable
iter
中的第二个参数是什么? 文档也不多说:https://docs.python.org/2/library/functions.html#iter and https://docs.python.org/3.6/library/functions.html#iter
根据文档:
Return an iterator object. The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, object must be a collection object which supports the iteration protocol (the iter() method), or it must support the sequence protocol (the getitem() method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. If the second argument, sentinel, is given, then object must be a callable object. The iterator created in this case will call object with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.
我想文档需要一些 "decrypting":
- 如果没有第二个参数,object 必须是一个支持迭代协议的集合对象(iter() 方法)
这是否意味着它需要来自 collections
?还是只要对象有一个__iter__()
就可以了?
- ,或者它必须支持序列协议(getitem() 方法,整数参数从 0 开始)
这有点神秘。那么这是否意味着它会尝试查看序列是否已编入索引并因此可查询,并且索引必须从 0 开始?这是否也意味着索引需要是连续的,即 0、1、2、3,...而不是像 0、2、8、13,...?
- 如果它不支持这些协议中的任何一个,则会引发 TypeError。
是的,这部分我明白=)
- 如果给出第二个参数 sentinel,则对象必须是可调用对象。
好的,现在这有点科幻了。将某物称为 sentinel
只是 Python 中的一个术语吗? sentinel
是什么意思 Python? "callable object" 就像它是一个函数而不是类型对象?
- 在这种情况下创建的迭代器将在每次调用其 next() 方法时调用不带参数的对象;
这部分我不太明白,也许一个例子会有所帮助。
- 如果返回的值等于sentinel,将引发StopIteration,否则将返回值。
好吧,所以这里的sentinel
指的是一些打破标准?
谁能帮忙解答一下decipher/clarify以上几点关于iter
的意思?
对于一个参数,iter
必须被赋予一个具有 __iter__
特殊方法、 或 __getitem__
特殊方法的对象。如果两者都不存在,iter
将 引发错误
>>> iter(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not iterable
有 2 个迭代协议。旧协议依赖于调用 __getitem__
来获取从 0 到引发 IndexError
的连续整数。新协议依赖于 return 从 __iter__
编辑而来的迭代器。
在Python2中,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>
要使您的自定义 class 可迭代,您需要 __iter__
或 __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
期望 iterables 的循环和方法将隐式创建迭代器:
>>> list(Foo())
[0, 1, 2, 3, 4]
>>> for i in Bar():
0
1
2
3
4
对于 2 参数形式,第一个参数必须是实现 __call__
的函数或对象。第一个参数在没有参数的情况下被调用; return 值是从迭代器中产生的。当该次迭代的函数调用的值 return 等于给定的 sentinel 值时,迭代停止,就好像通过:
value = func()
if value == sentinel:
return
else:
yield value
例如,要在骰子 之前 获得值,我们抛出 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]
为了进一步说明,每次在迭代器上使用 next()
时,都会在不带参数的情况下调用给定函数(或具有 __call__
特殊方法的给定对象):
>>> 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
(即 throw
被称为 throw()
,如果 returned 值不等于 6,则产生它。
或者在
的情况下
>>> fin_1byte = iter(functools.partial(fin.read, 1), '')
>>> for c in fin_1byte:
... print c,
从文件末尾的文件中读取 returns 空字符串(如果是二进制文件,则为空字节):
>>> from io import StringIO
>>> fin = StringIO(u'ab')
>>> fin.read(1)
u'a'
>>> fin.read(1)
u'b'
>>> fin.read(1)
u''
如果还没有到达文件末尾,将return编辑一个字符。
这也可用于从重复的函数调用中生成无限迭代器:
>>> dice = iter(throw, 7)
因为值 returned 永远不可能等于 7,迭代器永远运行。一个常见的习惯用法是使用匿名 object
来确保比较不会对任何可能的值
成功
>>> dice = iter(throw, object())
因为
>>> object() != object()
True
请注意,单词 sentinel 通常用于在某些数据中用作结束标记的值,并且不会在数据中自然出现,因为在 this Java answer.
让我们考虑一个文件:
$ echo -e """This is a foo bar sentence .\nAnd this is the first txtfile in the corpus .""" > test.txt
$ cat test.txt
This is a foo bar sentence .
And this is the first txtfile in the corpus .
当我想按字符读取文件时,我可以这样做 :
>>> fin = open('test.txt')
>>> while fin.read(1):
... fin.seek(-1,1)
... print fin.read(1),
...
T h i s i s a f o o b a r s e n t e n c e .
A n d t h i s i s t h e f i r s t t x t f i l e i n t h e c o r p u s .
但是使用 while 循环可能看起来有点不符合 Python 风格,尤其是。当我使用 fin.read(1)
检查 EOF 然后回溯以读取当前字节时。所以我可以做这样的事情 How to read a single character at a time from a file in Python?:
>>> import functools
>>> fin = open('test.txt')
>>> fin_1byte = iter(functools.partial(fin.read, 1), '')
>>> for c in fin_1byte:
... print c,
...
T h i s i s a f o o b a r s e n t e n c e .
A n d t h i s i s t h e f i r s t t x t f i l e i n t h e c o r p u s .
但是当我在没有第二个参数的情况下尝试它时,它会抛出一个 TypeError
:
>>> fin = open('test.txt')
>>> fin_1byte = functools.partial(fin.read, 1)
>>> for c in iter(fin_1byte):
... print c,
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'functools.partial' object is not iterable
iter
中的第二个参数是什么? 文档也不多说:https://docs.python.org/2/library/functions.html#iter and https://docs.python.org/3.6/library/functions.html#iter
根据文档:
Return an iterator object. The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, object must be a collection object which supports the iteration protocol (the iter() method), or it must support the sequence protocol (the getitem() method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. If the second argument, sentinel, is given, then object must be a callable object. The iterator created in this case will call object with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.
我想文档需要一些 "decrypting":
- 如果没有第二个参数,object 必须是一个支持迭代协议的集合对象(iter() 方法)
这是否意味着它需要来自 collections
?还是只要对象有一个__iter__()
就可以了?
- ,或者它必须支持序列协议(getitem() 方法,整数参数从 0 开始)
这有点神秘。那么这是否意味着它会尝试查看序列是否已编入索引并因此可查询,并且索引必须从 0 开始?这是否也意味着索引需要是连续的,即 0、1、2、3,...而不是像 0、2、8、13,...?
- 如果它不支持这些协议中的任何一个,则会引发 TypeError。
是的,这部分我明白=)
- 如果给出第二个参数 sentinel,则对象必须是可调用对象。
好的,现在这有点科幻了。将某物称为 sentinel
只是 Python 中的一个术语吗? sentinel
是什么意思 Python? "callable object" 就像它是一个函数而不是类型对象?
- 在这种情况下创建的迭代器将在每次调用其 next() 方法时调用不带参数的对象;
这部分我不太明白,也许一个例子会有所帮助。
- 如果返回的值等于sentinel,将引发StopIteration,否则将返回值。
好吧,所以这里的sentinel
指的是一些打破标准?
谁能帮忙解答一下decipher/clarify以上几点关于iter
的意思?
对于一个参数,iter
必须被赋予一个具有 __iter__
特殊方法、 或 __getitem__
特殊方法的对象。如果两者都不存在,iter
将 引发错误
>>> iter(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not iterable
有 2 个迭代协议。旧协议依赖于调用 __getitem__
来获取从 0 到引发 IndexError
的连续整数。新协议依赖于 return 从 __iter__
编辑而来的迭代器。
在Python2中,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>
要使您的自定义 class 可迭代,您需要 __iter__
或 __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
期望 iterables 的循环和方法将隐式创建迭代器:
>>> list(Foo())
[0, 1, 2, 3, 4]
>>> for i in Bar():
0
1
2
3
4
对于 2 参数形式,第一个参数必须是实现 __call__
的函数或对象。第一个参数在没有参数的情况下被调用; return 值是从迭代器中产生的。当该次迭代的函数调用的值 return 等于给定的 sentinel 值时,迭代停止,就好像通过:
value = func()
if value == sentinel:
return
else:
yield value
例如,要在骰子 之前 获得值,我们抛出 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]
为了进一步说明,每次在迭代器上使用 next()
时,都会在不带参数的情况下调用给定函数(或具有 __call__
特殊方法的给定对象):
>>> 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
(即 throw
被称为 throw()
,如果 returned 值不等于 6,则产生它。
或者在
的情况下>>> fin_1byte = iter(functools.partial(fin.read, 1), '')
>>> for c in fin_1byte:
... print c,
从文件末尾的文件中读取 returns 空字符串(如果是二进制文件,则为空字节):
>>> from io import StringIO
>>> fin = StringIO(u'ab')
>>> fin.read(1)
u'a'
>>> fin.read(1)
u'b'
>>> fin.read(1)
u''
如果还没有到达文件末尾,将return编辑一个字符。
这也可用于从重复的函数调用中生成无限迭代器:
>>> dice = iter(throw, 7)
因为值 returned 永远不可能等于 7,迭代器永远运行。一个常见的习惯用法是使用匿名 object
来确保比较不会对任何可能的值
>>> dice = iter(throw, object())
因为
>>> object() != object()
True
请注意,单词 sentinel 通常用于在某些数据中用作结束标记的值,并且不会在数据中自然出现,因为在 this Java answer.