Python 嵌套函数同名变量作用域
Python 嵌套函数间同名变量的作用域规则与 C++/Go/JS 稍有不同,对于读操作而言,Python 的行为与 C++/Go/JS 一致,通过 global/nonlocal 关键字还能做到更灵活,赋值操作则必须要使用 global/nonlocal 关键字才能实现对外层/全局变量的引用。
不过需要注意的是,在函数内部 Python 无法定义同名的局部变量,当然 C++/Go/JS 也无法做到在内层函数直接引用同名的全局变量,这是 Python 与 C++/Go/JS 非常大的不同。
C++
#include <iostream>
using namespace std;
int x = 0;
void outer() {
x = 1;
[&] { // middle
[&] { // inner
x = 2;
{ // local
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;
}
输出
~$ g++ -o var -std=c++11 var.cc
~$ ./var
local: 3
inner: 2
middle: 2
outer: 2
global: 2
Go
package main
import "fmt"
var x int = 0
func outer() {
x = 1
func() { // middle
func() { // inner
x = 2
{ // local
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)
}
输出
~$ go run var.go
local: 3
inner: 2
middle: 2
outer: 2
global: 2
JS(ES6)
#!/usr/bin/env node
let x = 0
outer = () => {
x = 1
middle = () => {
inner = () => {
x = 2
{ // local
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)
输出
~$ ./var.js
local: 3
inner: 2
middle: 2
outer: 2
global: 2
Python2
Python2 提供了 global 关键字可以在内层函数中显式引用全局变量,如果不使用 global,内层函数的读操作将引用外层函数的变量(如果没有外层函数,则引用全局变量),赋值操作将定义新变量,赋值操作的行为无法做到与 C++/Go/JS 保持一致(global 需要在首次引用同名变量前定义)。
#! /usr/bin/env python2
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))
输出
~$ ./var2.py
local: 3
inner: 3
middle: 1
outer: 1
global: 1
Python3
Python3 提供了新的关键字 nonlocal 用于显式引用外层函数的变量(nonlocal 需要在首次引用同名变量前定义),nonlocal 结合 global 使得 Python3 能够做到赋值操作的行为与 C++/Go/JS 保持一致。
#!/usr/bin/env python3
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))
输出
~$ ./var3.py
local: 3
inner: 3
middle: 1
outer: 1
global: 3
注意 nonlocal 不能引用全局变量。
#!/usr/bin/env python3
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))
输出
~$ ./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
最后修改于 2019-03-03