Python 嵌套函数间同名变量的作用域规则与 C++/Go/JS 稍有不同,对于读操作而言,Python 的行为与 C++/Go/JS 一致,通过 global/nonlocal 关键字还能做到更灵活,赋值操作则必须要使用 global/nonlocal 关键字才能实现对外层/全局变量的引用。
不过需要注意的是,在函数内部 Python 无法定义同名的局部变量,当然 C++/Go/JS 也无法做到在内层函数直接引用同名的全局变量,这是 Python 与 C++/Go/JS 非常大的不同。
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <iostream> using namespace std;int x = 0 ;void outer () { x = 1 ; [&] { [&] { x = 2 ; { int x = 3 ; cout << "local:\t" << x << endl; } cout << "inner:\t" << x << endl; }(); cout << "middle:\t" << x << endl; }(); cout << "outer:\t" << x << endl; } int main () { outer (); cout << "global:\t" << x << endl; return 0 ; }
输出
1 2 3 4 5 6 7 ~$ g++ -o var -std=c++11 var.cc ~$ ./var local : 3inner: 2 middle: 2 outer: 2 global: 2
Go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport "fmt" var x int = 0 func outer () { x = 1 func () { func () { x = 2 { x := 3 fmt.Println("local:\t" , x) } fmt.Println("inner:\t" , x) }() fmt.Println("middle:\t" , x) }() fmt.Println("outer:\t" , x) } func main () { outer() fmt.Println("global:\t" , x) }
输出
1 2 3 4 5 6 ~$ go run var.go local : 3inner: 2 middle: 2 outer: 2 global: 2
JS(ES6) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #!/usr/bin/env node let x = 0 outer = () => { x = 1 middle = () => { inner = () => { x = 2 { let x = 3 console .log ("local:\t" , x) } console .log ("inner:\t" , x) } inner () console .log ("middle:\t" , x) } middle () console .log ("outer:\t" , x) } outer ()console .log ("global:\t" , x)
输出
1 2 3 4 5 6 ~$ ./var.js local : 3inner: 2 middle: 2 outer: 2 global: 2
Python2 Python2 提供了 global 关键字可以在内层函数中显式引用全局变量,如果不使用 global,内层函数的读操作将引用外层函数的变量(如果没有外层函数,则引用全局变量),赋值操作将定义新变量,赋值操作的行为无法做到与 C++/Go/JS 保持一致(global 需要在首次引用同名变量前定义)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 x = 0 def outer (): global x x = 1 def middle (): def inner (): x = 2 if True : x = 3 print ('local:\t{0}' .format (x)) print ('inner:\t{0}' .format (x)) inner() print ('middle:\t{0}' .format (x)) middle() print ('outer:\t{0}' .format (x)) outer() print ('global:\t{0}' .format (x))
输出
1 2 3 4 5 6 ~$ ./var2.py local : 3inner: 3 middle: 1 outer: 1 global: 1
Python3 Python3 提供了新的关键字 nonlocal 用于显式引用外层函数的变量(nonlocal 需要在首次引用同名变量前定义),nonlocal 结合 global 使得 Python3 能够做到赋值操作的行为与 C++/Go/JS 保持一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 x = 0 def outer (): x = 1 def middle (): nonlocal x def inner (): global x x = 2 if True : x = 3 print ('local:\t{0}' .format (x)) print ('inner:\t{0}' .format (x)) inner() print ('middle:\t{0}' .format (x)) middle() print ('outer:\t{0}' .format (x)) outer() print ('global:\t{0}' .format (x))
输出
1 2 3 4 5 6 ~$ ./var3.py local : 3inner: 3 middle: 1 outer: 1 global: 3
注意 nonlocal 不能引用全局变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 x = 0 def outer (): global x x = 1 def middle (): nonlocal x def inner (): global x x = 2 if True : x = 3 print ('local:\t{0}' .format (x)) print ('inner:\t{0}' .format (x)) inner() print ('middle:\t{0}' .format (x)) middle() print ('outer:\t{0}' .format (x)) outer() print ('global:\t{0}' .format (x))
输出
1 2 3 4 5 ~$ ./var3.py File "./var3.py" , line 9 nonlocal x ^ SyntaxError: no binding for nonlocal 'x' found
参考资料 Scope of Variables in Python Tutorial
https://www.datacamp.com/community/tutorials/scope-of-variables-python