1. 什么是作用域
作用域定义了在程序的某一部分可以访问的变量和对象的范围。Python通过作用域来解决命名冲突问题,并确保程序中不同区域的代码能够正确引用所需的变量。
Python有不同类型的作用域,主要体现在变量的查找路径上。Python的作用域遵循一个叫做LEGB规则的查找顺序:
- L(Local) :局部作用域,即当前函数或方法内部的作用域。
- E(Enclosing) :闭包作用域,指的是包含当前函数的外部函数作用域。
- G(Global) :全局作用域,指的是当前模块的作用域。
- B(Built-in) :内建作用域,指的是Python解释器内置的命名空间。
当你引用一个变量时,Python会从内到外按此顺序查找,直到找到该变量或引发NameError异常。
2. Python中的四种作用域
2.1 局部作用域(Local Scope)
局部作用域是指变量在函数内部的作用范围。当你在函数内部定义一个变量时,它只在该函数内部可见,外部代码无法访问。这个作用域的存在确保了不同函数中的同名变量互不干扰。
def my_function():
x = 10 # 局部变量
print(x)
my_function()
# print(x) # 会抛出NameError,因为x在函数外部不可见
在上述代码中,变量x仅在my_function()函数内部可见。
2.2 闭包作用域(Enclosing Scope)
闭包作用域指的是包含当前函数的外部函数的作用域。如果一个函数被另一个函数包围,那么被包围的函数可以访问外部函数的变量。这种变量也称为自由变量。
def outer():
x = 10 # 外部函数中的变量
def inner():
print(x) # 内部函数可以访问外部函数的变量
inner()
outer()
在这段代码中,inner()函数可以访问outer()函数中的x,这就是闭包作用域的特性。
2.3 全局作用域(Global Scope)
全局作用域是指在模块级别定义的变量或函数。全局变量可以在整个模块中访问,除非在局部作用域中使用global关键字进行声明,否则局部作用域不能修改全局变量。
x = 10 # 全局变量
def my_function():
print(x) # 可以访问全局变量
my_function()
在上面的代码中,x是一个全局变量,可以在my_function()函数内被访问和使用。
2.4 内建作用域(Built-in Scope)
内建作用域是Python解释器为每个程序运行时自动提供的命名空间。它包含了Python的内置函数、异常、对象类型等内容,如print(), len(), range()等。
print(len("Hello")) # len 是内建函数
内建作用域是所有作用域中最外层的,任何时候你都可以访问内建命名空间中的对象。
3. LEGB查找规则
Python根据LEGB规则查找变量。当你在程序中引用一个变量时,Python将按照以下顺序查找:
- Local:首先查找局部作用域中的变量。
- Enclosing:如果局部作用域没有找到,查找封闭函数中的变量。
- Global:如果都没有找到,查找全局作用域中的变量。
- Built-in:如果在全局作用域中仍未找到,最后查找内建作用域。
示例:
x = 5 # 全局变量
def outer():
x = 10 # 外部函数中的变量
def inner():
x = 15 # 局部变量
print(x) # 打印的是局部变量x
inner()
outer()
在这个例子中,inner()函数打印的是局部变量x的值(15),而不是外部函数或全局作用域中的x。这说明Python遵循LEGB规则从局部作用域开始查找变量。
4. global与nonlocal关键字
Python提供了global和nonlocal关键字,用于修改变量的作用域。
-
global:用于声明一个全局变量,这样你可以在函数内部修改全局变量的值。
x = 5 def modify_global(): global x x = 10 modify_global() print(x) # 输出 10 -
nonlocal:用于在嵌套函数中声明一个变量是来自于外部函数的作用域,从而修改外部函数中的变量。
def outer(): x = 5 def inner(): nonlocal x x = 10 inner() print(x) # 输出 10 outer()