Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python的目的是什么';重复一遍?_Python_Python 3.x_Itertools - Fatal编程技术网

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']

对于Python类的每一次使用,我都可以想到另一个同样(可能更)可接受的解决方案来实现相同的效果。例如:

>>> [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的内存使用问题