3

我是一个非常新手的程序员。我正在尝试使用模块combinations中的工具。itertools所以我尝试:

from itertools import *
print combinations('12345', 3)

('123', '124', '125', [...])但我得到的不是预期的<itertools.combinations object at [pointer]>。我很困惑,因为在其他模块中调用方法会返回预期的结果,例如:

import random
print random.randrange(10)
>>> 9

我对 itertools 模块做错了什么?

4

4 回答 4

6

没有。结果是应该的。您显然没有考虑的是结果是一个迭代器,而不是一个完全评估的结果列表/元组。您看到的输出是repr()该对象的输出(它返回字符串)。您可以通过将前者传递给list构造函数将前者转换为后者:

import itertools
print list(itertools.combinations('12345', 3))

但是当您不需要它并且您只是迭代这些值时,它不会同时存储所有结果,从而节省了大量内存。它还允许通过不消耗整个迭代器来避免工作(例如,找到满足某些条件的第一个组合然后返回)。

于 2012-11-14T20:34:05.327 回答
3

itertools.combinations返回一个可迭代的(您可以在 Python 文档中给出的等效代码yield中看到关键字的使用)。如果要打印完整序列,可以使用。list(combinations(...))

>>> print list(combinations('12345', 3))
[('1', '2', '3'), ('1', '2', '4'), ('1', '2', '5'), ('1', '3', '4'), ('1', '3', '5' ('2', '3', '5'), ('2', '4', '5'), ('3', '4', '5')]
于 2012-11-14T20:32:28.747 回答
2

那是一个迭代器。您可以将其转换为 a listortuple使用list(combinations('12345', 3))or tuple(combinations('12345', 3))

根据您的问题,我认为您可能对什么是序列、可迭代对象和迭代器有些困惑。我认为完全理解它们以便能够编写和/或理解 python 代码是很有用的,所以我会试着给你一个关于这个问题的解释。

list对象tuple序列。序列是支持某些特定操作的对象。即它们是可迭代的(你可以这样做for elem in sequence),它们支持“项目访问”(sequence[key]有效)它们具有“长度”(len(sequence)有效)并且您可以检查项目是否在序列中(elem in sequence有效)。[有构成“序列协议”的操作的完整列表。唉,它是特定于 C-API 的。然而,这些函数的名称和解释应该让您了解它们支持的完整操作集]

在 python 中,还有另外两种对象在某些情况下可以用来代替序列:iterablesiterators

可迭代对象是支持迭代的对象。说到python,如果一个对象有一个__iter__返回迭代器的方法,它就是可迭代的。

迭代器是一个对象,它在一个可迭代对象上迭代一次并一个一个地产生值。在 python 中,迭代器是一个实现__iter__and__next__方法的对象(next在 python2 中)。__iter__ 通常“什么都不做”,只是返回对象本身。该next方法返回迭代中的下一个值。

现在,combinations('12345', 3)是一个可迭代对象,这意味着您可以遍历它,但您无法使用iterable[key]语法访问它的项目,也无法使用len.

为什么要使用迭代器?在某些情况下,您可以避免将整个值序列放入内存以对其进行迭代。例如,如果您想遍历数字1100则不必创建一个充满数字list的长度并对其进行迭代。100给出一个可以计算下一个相加的值1

所以基本上可迭代是一种减少内存使用的方法,并且通常是“循环某些东西”所需的功能的抽象。如果你想要一个序列,你可以如前所述转换它们。

一种特殊的迭代器是所谓的生成器。生成器只是可以使用函数语法编写的迭代器,特别是它们使用yield关键字:

>>> def numbers(n):
...     while n > 0:
...             yield n
...             n -= 1
... 
>>> numbers(5)
<generator object numbers at 0xb744a93c>
>>> for elem in numbers(5):
...     print elem
... 
5
4
3
2
1

如您所见,当您调用numbers代码时执行。相反,python 创建了一个生成器对象,它是一个迭代器。当您迭代对象时,函数内的代码将被执行,直到yield遇到。发生这种情况时,返回“参数”yield并冻结执行。当新的迭代开始时,它会重新开始。

或许你可以在这个例子中更好地看到执行流程:

>>> def flow():
...     yield 'Execution stopped here'
...     yield 'Execution continues'
...     yield 'Execution ended'
... 
>>> generator = flow()
>>> next(generator)   #same as generator.__next__()
'Execution stopped here'
>>> next(generator)
'Execution continues'
>>> next(generator)
'Execution ended'
>>> next(generator)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

您可能有兴趣阅读提出它们的PEP255 。实际上它们已经被扩展以提供协程功能,但我认为这已经足够了。

于 2012-11-14T21:06:13.070 回答
0

itertools.combination是一个类;因此,调用itertools.combinations()会返回该类的实例实例,可以对其进行迭代以获取值:

for combo in combinations('12345', 3):
    print combo
于 2012-11-14T20:33:21.547 回答