在Python2.7.6中列出迭代器和在迭代器上迭代的区别

在Python2.7.6中列出迭代器和在迭代器上迭代的区别,python,python-2.7,Python,Python 2.7,我最近一直在玩一些涉及迭代器的代码: """IntegerPartitions.py Generate and manipulate partitions of integers into sums of integers. D. Eppstein, August 2005. https://www.ics.uci.edu/~eppstein/PADS/IntegerPartitions.py """ def mckay(n): """ Integer partition

我最近一直在玩一些涉及迭代器的代码:

"""IntegerPartitions.py

Generate and manipulate partitions of integers into sums of integers.

D. Eppstein, August 2005.

https://www.ics.uci.edu/~eppstein/PADS/IntegerPartitions.py
"""

def mckay(n):
    """
    Integer partitions of n, in reverse lexicographic order.
    The output and asymptotic runtime are the same as mckay(n),
    but the algorithm is different: it involves no division,
    and is simpler than mckay, but uses O(n) extra space for
    a recursive call stack.
    """
    if n == 0:
        yield []
    if n <= 0:
        return
    for p in mckay(n-1):
        if len(p) == 1 or (len(p) > 1 and p[-1] < p[-2]):
            p[-1] += 1
            yield p
            p[-1] -= 1
        p.append(1)
        yield p
        p.pop()
分区似乎不会显示,除非我逐个打印它们。这是语言中的错误(我的版本是UbuntuTrusty上的Python2.7.6),还是我遗漏了什么?我在谷歌上四处搜索,似乎找不到任何与此相关的信息

我认为这可能与递归调用有关,但我用下面的代码进行了尝试,并发现了类似的结果

def mckay(n):
    """
    Integer partitions of n, in reverse lexicographic order.
    Note that the generated output consists of the same list object,
    repeated the correct number of times; the caller must leave this
    list unchanged, and must make a copy of any partition that is
    intended to last longer than the next call into the generator.
    The algorithm follows Knuth v4 fasc3 p38 in rough outline.
    """
    if n == 0:
        yield []
    if n <= 0:
        return
    partition = [n]
    last_nonunit = (n > 1) - 1
    while True:
        yield partition
        if last_nonunit < 0:
            return
        if partition[last_nonunit] == 2:
            partition[last_nonunit] = 1
            partition.append(1)
            last_nonunit -= 1
            continue
        replacement = partition[last_nonunit] - 1
        total_replaced = replacement + len(partition) - last_nonunit
        reps,rest = divmod(total_replaced,replacement)
        partition[last_nonunit:] = reps*[replacement]
        if rest:
            partition.append(rest)
        last_nonunit = len(partition) - (partition[-1]==1) - 1

问题是函数
mckay
正在修改同一个列表对象,因此当您对其调用
list()
时,实际上会得到一个包含4个项目的列表,这些项目实际上指向同一个对象。因此,正如列表对象最后是空的一样,您得到的只是带有空列表的列表

>>> p = mckay(4)
>>> [id(x) for x in p]
[139854369904832, 139854369904832, 139854369904832, 139854369904832, 139854369904832]

>>> for x in mckay(4):
    print x, '-->', id(x)

[4] --> 140446845125552
[3, 1] --> 140446845125552
[2, 2] --> 140446845125552
[2, 1, 1] --> 140446845125552
[1, 1, 1, 1] --> 140446845125552
>>> x # The actual list object is empty at the end of the iteration
[]
>>> id(x)
140446845125552
但是,当您在其上循环时,您只是立即打印返回的对象,因此输出不同,这里的修复方法是生成一个浅拷贝:

yield p[:]
>>> p = mckay(4)
>>> [id(x) for x in p]
[139854369904832, 139854369904832, 139854369904832, 139854369904832, 139854369904832]

>>> for x in mckay(4):
    print x, '-->', id(x)

[4] --> 140446845125552
[3, 1] --> 140446845125552
[2, 2] --> 140446845125552
[2, 1, 1] --> 140446845125552
[1, 1, 1, 1] --> 140446845125552
>>> x # The actual list object is empty at the end of the iteration
[]
>>> id(x)
140446845125552
yield p[:]