接下来是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)是通过unLoalLoalError的行,而我所引用的SO问题解释了为什么。然而,标线3的作品!
默认情况下,列表在python中是通过引用复制的,因此当c c更改时,c更改是可以理解的。但是,如果python不允许直接从方法的作用域更改a和b,那么为什么首先要允许c更改呢?
我不明白python中默认通过引用复制列表这一事实应该如何使这个设计决策不一致。
我在想什么?
更新:
为了完整性,我还添加了与上述问题等价的字典,即我添加了源代码,并用“cc>标记了更新”。
为了进一步完善,我还添加了SET等价物。对我来说,这部片子的表现真是出人意料。我希望它的行为类似于列表和字典…
最佳答案
与字符串和整数不同,python中的列表是可变对象。这意味着它们是被设计来改变的。线路
c[0] += 'c'
与所说的一模一样
c.__setitem__(0, c.__getitem__(0) + 'c')
它不会对
c
绑定到的名称做任何更改。在这个调用之前和之后,c
是同一个列表,只是这个列表的内容发生了变化。你说过吗
c += ['c']
c = [42]
在函数
f()
中,会出现相同的UnboundLocalError
,因为第二行使c
成为本地名称,第一行转换为c = c + ['c']
要求名称
c
已绑定到某个(在本地范围内)尚未绑定的对象。