跟进Reason for unintuitive UnboundLocalError behaviour(我假设你已经阅读过了)。 请考虑以下Python脚本:
def f():
# a+=1 # 1
aa=a
aa+=1
# b+='b' # 2
bb=b
bb+='b'
c[0]+='c' # 3
c.append('c')
cc=c
cc.append('c')
d['d']=5 # Update 1
d['dd']=6 # Update 1
dd=d # Update 1
dd['ddd']=7 # Update 1
e.add('e') # Update 2
ee=e # Update 2
ee.add('e') # Update 2
a=1
b='b'
c=['c']
d={'d':4} # Update 1
e=set(['e']) # Update 2
f()
print a
print b
print c
print d # Update 1
print e # Update 2
脚本的结果是:
1
b
['cc', 'c', 'c']
{'dd': 6, 'd': 5, 'ddd': 7}
set(['e'])
注释掉的行(标记为1,2)是通过UnboundLocalError的行,我引用的SO问题解释了原因。但是,标记为3的行有效!
默认情况下,列表在Python中通过引用复制,因此当cc更改时c更改是可以理解的。但是,如果Python不允许直接从方法的范围更改a和b,那么为什么Python允许c首先进行更改?
我不知道默认列表是如何通过Python中的引用复制的,这会使这个设计决策不一致。
我错过了什么人?
更新
# Update
答案 0 :(得分:3)
与字符串和整数不同,Python中的列表是可变对象。这意味着它们的设计可以改变。这条线
c[0] += 'c'
与说
相同c.__setitem__(0, c.__getitem__(0) + 'c')
不会对名称c
绑定的内容进行任何更改。在此次通话之前和之后,c
是相同的列表 - 此列表的内容已更改。
你说过
c += ['c']
c = [42]
函数f()
中的,会出现相同的UnboundLocalError
,因为第二行会使c
成为本地名称,第一行会转换为
c = c + ['c']
要求名称c
已经绑定到某个东西,(在本地范围内)它还没有。
答案 1 :(得分:2)
要考虑的重要一点是:(或b或c)指的是什么对象?第a += 1
行正在改变a引用的整数。整数是不可变的,所以当从1变为2时,它与a = a + 1
实际上是相同的,它提供了一个全新的整数来引用。
另一方面,c[0] += 'c'
不会更改c引用的列表,它只会更改其第一个元素引用的字符串。列表是可变的,因此可以在不改变其标识的情况下修改相同的列表。