Python中int与list的作用域差异原因解析
两段Python代码行为差异的底层原因解释
先看两段代码的实际运行表现:
代码1(触发错误)
# code 1 # makes an error def func1(): a += 1 a = 1 try: func1() print(a) except UnboundLocalError as e: print(e)
运行后会输出:local variable 'a' referenced before assignment
代码2(正常执行)
# code 2 # makes no errors def func2(): b.append(1) b = [] func2() print(b)
运行后会输出:[1]
核心原因:变量作用域规则 + 可变/不可变对象的操作差异
Python的作用域判定逻辑:函数内部对变量的操作类型,直接决定了Python如何识别变量的作用域:
- 如果函数内存在对变量的赋值操作(包括
+=这类语法糖,本质是重新赋值),Python会默认将该变量标记为局部变量,优先在函数局部作用域查找。 - 如果函数内只是调用变量指向对象的方法、修改对象内部数据(没有改变变量本身的指向),Python会去全局作用域查找该变量。
- 如果函数内存在对变量的赋值操作(包括
针对两段代码的具体分析:
- 代码1中,
a += 1等价于a = a + 1,属于对变量a的赋值操作。Python编译func1时,会把a标记为局部变量,但函数内部并没有提前定义a,执行时尝试读取局部a的值来计算,就会触发UnboundLocalError。 - 代码2中,
b.append(1)是调用列表对象的append方法,修改的是b指向的列表本身的内容,并没有改变变量b的指向(b依然指向原来的空列表)。Python不会把b标记为局部变量,会去全局作用域找到b对应的列表对象,执行修改操作,因此可以正常运行。
- 代码1中,
可变/不可变对象的本质影响:
这背后的差异也和Python对象的可变性直接相关:a是不可变的int类型,要改变它的值只能通过重新赋值(让a指向新的int对象),这必然触发赋值操作,被判定为局部变量。b是可变的list类型,修改列表内容不需要改变b的指向,只需要操作已有对象的内部数据,因此不会触发局部变量的判定。
内容的提问来源于stack exchange,提问作者심재승
相关产品推荐
相关产品推荐

