當您詢問變量值時,Python遵循LEGB規則:local,enclosing,global,built-in。
但是當你分配一個變量,它是在局部範圍內產生從頭(假設變量賦值是內部功能),丟棄任何值之前綁定到它:
a = 5
def f(x):
print a # Prints `5`, because name `a` can be found following LEGB rule in Global scope.
print x # Prints whatever value `x` was having, found following LEGB rule in Local scope.
x = 123 # Forgets previous value of `x`, re-assign it to `123` in the Local scope.
你的問題與無約束變量出現在這裏:a += 1
只是一個語法糖a = a + 1
。當你這樣做a = a + 1
,Python中捕捉任何a
是本地的,所以它的字節碼產生LOAD_FAST命令:
import dis
a = 1
def f():
a += 1
print dis.dis(f)
0 LOAD_FAST 0 (a)
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_FAST 0 (a)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
LOAD_FAST用於局部變量取。但是當您調用LOAD_FAST時,您在本地範圍內沒有a
,因此命令失敗。
其實,如果你沒有分配到a
,但是想從本地範圍修改它,你可以通過方法調用來完成。不幸的是,int
沒有修改的方法,所以我給帶班爲例:
class Number(object):
def __init__(self, x):
self.x = x
def add_one(self):
self.x += 1
a = Number(1)
def f():
a.add_one()
print a.x
print a.x
f()
print a.x
1
2
2
在這裏,你基本上是做a=a+1
,但在更復雜的方式。這是因爲對a
的調用被解析爲全局(並且工作正常),並且您不在f()
內執行任何分配。方法add_one
在現有對象上調用 - 它不關心調用者是全局還是本地。
在你的第二段代碼中,你不需要'global' – gil
@gill更正,謝謝 – tinySandy