Python的目的是什么';重复一遍?
对于Python类的每一次使用,我都可以想到另一个同样(可能更)可接受的解决方案来实现相同的效果。例如:Python的目的是什么';重复一遍?,python,python-3.x,itertools,Python,Python 3.x,Itertools,对于Python类的每一次使用,我都可以想到另一个同样(可能更)可接受的解决方案来实现相同的效果。例如: >>> [i for i in itertools.repeat('example', 5)] ['example', 'example', 'example', 'example', 'example'] >>> ['example'] * 5 ['example', 'example', 'example', 'example', 'example']
>>> [i for i in itertools.repeat('example', 5)]
['example', 'example', 'example', 'example', 'example']
>>> ['example'] * 5
['example', 'example', 'example', 'example', 'example']
>>> list(map(str.upper, itertools.repeat('example', 5)))
['EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE']
>>> ['example'.upper()] * 5
['EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE']
from itertools import repeat
fruits = ['apples', 'oranges', 'bananas']
# Initialize inventory to zero for each fruit type.
inventory = dict( zip(fruits, repeat(0)) )
在任何情况下,
itertools.repeat()
是最合适的解决方案吗?如果是,在什么情况下?您的foo*5
示例表面上看起来与itertools相似。重复(foo,5)
,但实际上完全不同
如果你写foo*100000
,口译员必须先创建100000份foo
,然后才能给你答案。因此,这是一个非常昂贵且对内存不友好的操作
但是,如果您编写itertools.repeat(foo,100000)
,解释器可以返回一个迭代器,该迭代器服务于相同的函数,并且在您需要它之前不需要计算结果——比如,在希望知道序列中每个结果的函数中使用它
这就是迭代器的主要优点:它们可以推迟对列表的一部分(或全部)的计算,直到您真正需要答案为止。这是一个迭代器。这里有一条重要线索:它在itertools模块中。从您链接到的文档中: itertools.重复(对象[,次]) 制作一个反复返回对象的迭代器。除非指定了times参数,否则将无限期运行 所以你永远不会把这些东西都记在记忆里。您想要使用它的示例可能是
n = 25
t = 0
for x in itertools.repeat(4):
if t > n:
print t
else:
t += x
因为这将允许您任意数量的
4
s,或者您可能需要的任何东西。itertools.repeat函数是惰性的;它只使用一项所需的内存。另一方面,(a,)*n
和[a]*n
习惯用法在内存中创建对象的n个副本。对于五个项目,乘法习语可能更好,但是如果您必须重复某个项目,例如,一百万次,您可能会注意到资源问题
尽管如此,很难想象itertools.repeat的许多静态用途。但是,事实上,itertools.repeat
是一个函数,允许您在许多功能应用程序中使用它。例如,您可能有一些库函数func
,它对输入的一个iterable进行操作。有时,您可能会预先构建各种项目的列表。其他时候,您可能只想在一个统一的列表上操作。如果列表很大,itertools.repeat
将节省内存
最后,repeat
使itertools
文档中描述的所谓“迭代器代数”成为可能。即使是itertools
模块本身也使用repeat
功能。例如,以下代码是作为itertools.izip_longest
的等效实现给出的(尽管实际代码可能是用C编写的)。注意从底部开始使用重复七行:
class ZipExhausted(Exception):
pass
def izip_longest(*args, **kwds):
# izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
fillvalue = kwds.get('fillvalue')
counter = [len(args) - 1]
def sentinel():
if not counter[0]:
raise ZipExhausted
counter[0] -= 1
yield fillvalue
fillers = repeat(fillvalue)
iterators = [chain(it, sentinel(), fillers) for it in args]
try:
while iterators:
yield tuple(map(next, iterators))
except ZipExhausted:
pass
itertools.repeat的主要目的是提供一个常量值流,用于map或zip:
第二个目的是,它提供了一种非常快速的方法来循环固定次数,如下所示:
for _ in itertools.repeat(None, 10000):
do_something()
这比:
for i in range(10000):
do_something().
前者获胜,因为它只需要更新现有None对象的引用计数。后者会丢失,因为range()或xrange()需要生成10000个不同的整数对象
注意,Guido自己在模块中使用了快速循环技术。见以下来源:
如前所述,它可以与zip
配合使用:
另一个例子:
>>> [i for i in itertools.repeat('example', 5)]
['example', 'example', 'example', 'example', 'example']
>>> ['example'] * 5
['example', 'example', 'example', 'example', 'example']
>>> list(map(str.upper, itertools.repeat('example', 5)))
['EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE']
>>> ['example'.upper()] * 5
['EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE', 'EXAMPLE']
from itertools import repeat
fruits = ['apples', 'oranges', 'bananas']
# Initialize inventory to zero for each fruit type.
inventory = dict( zip(fruits, repeat(0)) )
结果:
{'apples':0,'oranges':0,'panana':0}
要做到这一点而不重复,我必须涉及len(fruits)
我通常将重复与链和循环结合使用。以下是一个例子:
from itertools import chain,repeat,cycle
fruits = ['apples', 'oranges', 'bananas', 'pineapples','grapes',"berries"]
inventory = list(zip(fruits, chain(repeat(10,2),cycle(range(1,3)))))
print inventory
将前两个水果作为值10,然后循环剩余水果的值1和2。为什么不在范围(100000)内的i中使用:
然后访问循环中的foo
,而不是询问此函数您给它的值是多少?@TylerCrompton:迭代器可以传递给其他需要任何迭代器的对象,而不考虑其内部内容。你不能对一个范围做同样的事情(它是可编辑的,但它本身不是迭代器)。我明白你的意思,但就你评论的结尾而言,在Python3中?range
在Python3中是一个迭代器,但在Python2中,它返回一个列表。在Python2中,对迭代器使用xrange
;在Python3中,使用list(range(…)
作为列表。对不起,我没有看到这个问题被标记为Python-3。是的,@mleflovor是正确的。您可以将第3行更改为,而将第7行上的x
更改为4
,这样做的效果完全相同,可读性更强,速度更快。这就是为什么我想知道它是否有任何用途。@TylerCrompton:注意:有趣的是,在Python 2上,而True:
会比itertools中x的慢。重复(4):
,因为True
当时不是关键字,所以虽然为True:
实际加载了它,并在每个循环上测试了它的真实性,以确保没有人重新分配它(而1:
是一个真正的无限循环)repeat
将迭代器保留在堆栈上(内置范围内没有查找),并保存了该工作。谢天谢地,在Python3上,True
和False
是关键字,而True:
在字节码级别实际上是一个无条件无限循环。它创建对单个副本的n个引用。在某些情况下,差异可能非常显著;尝试a=[[]]*5;a[0]。追加(1)
。很好。我总是忘记Python中几乎所有的东西都是引用。我想这也减轻了som的内存使用问题