4
In [38]: d = set(range(3))

In [39]: d
Out[39]: set([0, 1, 2])

In [40]: for i in d:
    d  -= set([2])
   ....:     
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
/home/gridlex/workspace/HomeBackSites/nava_scripts/<ipython-input-40-b79926ab34ec> in <module>()
----> 1 for i in d:
      2     d  -= set([2])
      3 

RuntimeError: Set changed size during iteration

python中这两个赋值有什么区别?

1. d -= 集合([2])

2 d = d - 集合([2])

In [41]: d = set(range(3))

In [42]: for i in d:
    d = d - set([2])
   ....:     

In [43]: d
Out[43]: set([0, 1])
4

1 回答 1

3

对于像整数这样的不可变类型,a -= b与 相同a = a - b:它创建一个新值 ,a - b并重新绑定名称a以引用该新值而不是旧值。

但是对于像集合这样的可变类型,会更改原地指向a -= b的值。a(它还会重新绑定a到它已经引用的相同值,但这并不重要。)

最好的方法是查看对象的身份:

>>> s1 = set(range(3))
>>> s2 = s1
>>> s1, id(s1), s2, id(s2)
({0, 1, 2}, 4303749432, {0, 1, 2}, 4303749432)
>>> s1 -= {1}
>>> s1, id(s1), s2, id(s2)
({0, 2}, 4303749432, {0, 2}, 4303749432)
>>> s1 = s1 - {2}
>>> s1, id(s1), s2, id(s2)
({0}, 4303749664, {0, 2}, 4303749432)

请注意,-=叶子s1仍然引用与 相同的集合s2,并更改该集合;-叶子指的s1是全新的套装,不同的id是,不影响s2


在幕后,a = a - b大致* 相当于a = a.__sub__(b),而a -= b相当于a = a.__isub__(b)。除了如果没有__isub__方法,a -= b就用__sub__代替。

__isub__更改值,同时返回一个新值的事实__sub__并没有真正由语言强制执行,但对于所有内置类型和 stdlib 类型都是如此,并且预计对于任何自定义类型都是如此。它在文档中模拟数字类型中进行了描述:

这些 [ __ifoo__] 方法应该尝试就地执行操作(修改self)并返回结果(可以是但不一定是self)。如果未定义特定方法,则扩充分配回退到正常方法。例如,要执行语句x += y,其中x是具有__iadd__()方法的类的实例,x.__iadd__(y)被调用。如果x是一个没有定义__iadd__()方法的类的实例,x.__add__(y)并且y.__radd__(x)与 的求值一样被考虑x + y


*由于 (a) 、 (b) 在 C 中实现的类型(如) 和 (c) 查找某些特殊方法的规则与普通方法不同,因此它并不完全等价。__rsub__set

于 2013-11-13T18:29:45.300 回答