【问题标题】:Temporary created during python list iteration?在 python 列表迭代期间临时创建?
【发布时间】:2012-04-06 03:26:20
【问题描述】:

我想了解为什么会发生以下情况。我的猜测是在列表迭代期间正在创建一个临时的,但希望一些专家确认这一点:

def test():
    a=[set([1,2,3]),set([3,4,5])]
    x=set([1,4])
    for i in a:
        # doesn't actually modify list contents, making a copy of list elements in i?
        i=i.difference(x)
    print a
    for idx,i in enumerate(a):
        i=i.difference(x)
        print id(i),id(a[idx])
        # obviously this modifies the contents
        a[idx]=i
    print a

输出:

[set([1, 2, 3]), set([3, 4, 5])]
59672976 59672616
59672616 59672736
[set([2, 3]), set([3, 5])]

另外,我想了解为什么第二次迭代中 i 的“id”与 a[0] 的“id”相同。

【问题讨论】:

  • @Series8217 我已经看过这个,但更多的是在迭代时修改实际序列本身,而我正在谈论修改序列的内容。不过还是谢谢。

标签: python list iteration


【解决方案1】:

让我们一步一步来:

  1. i.difference(x) 不会修改 ix。相反,它返回一个新集合。
  2. i = i.difference(x) 重新绑定变量i 指向新的集合。它不会以任何方式影响列表的内容。
  3. a[idx] = i 确实通过将其 idx-th 元素设置为新集合来修改列表。

更简洁的实现可能会使用不同的变量,而不是重新利用 i

def test():
    a=[set([1,2,3]),set([3,4,5])]
    x=set([1,4])
    for i in a:
        diff=i.difference(x)
        # a[idx]=diff
    print a

【讨论】:

  • 所以 i 是一个临时的,是序列元素之一的副本,对吧?
  • @Sid:在 Python 中,没有 temporary(在 C++ 意义上)这样的东西。您的代码所做的是重用名为i 的变量来存储i.difference(x) 的结果。请参阅我更新的答案,以更简洁的方式编写相同的代码。
  • 实际上,LC 和基因组确实会产生一种临时性。
  • @aix 你能看看我关于“i”的“id”与a[0]的“id”的更新吗?这就是你所说的“重用”吗?
  • @Sid:不,它是对序列中元素之一的引用。如果这个元素恰好是一个可变对象,您可以就地修改它。例如,假设i 是一个列表,那么i.append(1) 会将1 附加到集合内的列表中。分配给i 只会将名称i 重新绑定到另一个对象。混淆源于这样一个事实,即对于整数等不可变对象,赋值和变异之间没有明显的区别。
【解决方案2】:

是的,当您执行i=i.difference(x) 时,它会创建一个新的i。只需像这样修改您的代码即可了解正在发生的事情 -

def test():
    a=[set([1,2,3]),set([3,4,5])]
    x=set([1,4])
    for i in a:
        # doesn't actually modify list contents, making a copy of list elements in i?
        print 'old i - ', id(i)
        i=i.difference(x)
        print 'new i - ', id(i)
    print a

test()

输出 -

old i -  4467059736
new i -  4467179216
old i -  4467177360
new i -  4467179216
[set([1, 2, 3]), set([3, 4, 5])]

【讨论】:

  • 我添加了行 print id(i),id(a[idx]) 并得到了以下 id: 59672976 59672616 59672616 59672736 所以显然 i 与对应的 a[idx 的 id 不同] 但我发现奇怪的是 a[0] 的 id 在下一次迭代中被分配给 i 。也许这就是@aix 重用的意思?
【解决方案3】:

您对 set.difference() 的使用表明您不知道集合的运算符 -=

def test():
    a=[set([1,2,3]),set([3,4,5])]
    x=set([1,4])
    for i in a:
        i -= x
    print a

这表明i 只是另一个指向您要修改的集合的指针。只是不要覆盖你的指针!

【讨论】:

  • 我发现这在语义上很奇怪 i-=x 实际上修改了指针,而 i=i-x 修改了指针。传统上人们会认为 i-=x 和 i=i-x 是等价的,不是吗?
  • @Sid = 是赋值运算符。 -= 是一个“增强的”赋值,它只评估一次目标,并在可能的地方修改它。请参阅augmented assignment expressions 的文档。
  • 这两种语法i = i - xi -= x 也有不同的方法是有充分理由的(即__sub__()__isub__() ;-)
  • @Series8217 谢谢,那部分很有帮助。
【解决方案4】:

这有助于以图形方式查看,因为它基本上是一个指针问题。

for i in a 迭代地将i 分配给a 中的每个元素。

i = i.difference(x) 创建 并将i 分配给它。

【讨论】:

    猜你喜欢
    • 2018-12-19
    • 1970-01-01
    • 1970-01-01
    • 2017-09-04
    • 2019-12-26
    • 2013-01-29
    • 2019-12-29
    • 2013-09-03
    • 2018-10-22
    相关资源
    最近更新 更多