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 - = set([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])
答案 0 :(得分: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类型都是正确的,并且预计适用于任何自定义类型。它在文档中的Emulating numeric types中描述:
这些[
__ifoo__
]方法应该尝试就地执行操作(修改 self )并返回结果(可能是,但不一定是自)。如果未定义特定方法,则扩充分配将回退到常规方法。例如,要执行语句x += y
,其中 x 是具有__iadd__()
方法的类的实例,则调用x.__iadd__(y)
。如果 x 是未定义__iadd__()
方法的类的实例,则会考虑x.__add__(y)
和y.__radd__(x)
,与{{1}的评估一样}。
*由于(a)x + y
,(b)用C实现的类型(如__rsub__
)和(c)查找规则,因此 某些特殊方法与普通方法不同。