接下来是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已绑定到某个(在本地范围内)尚未绑定的对象。

07-26 09:10
查看更多