今天我们要讲的是关于作用域的关键词:nonlocal
太长有空再看,先来看个大概
- nonlocal 的面貌
- nonlocal 多了解一点
- 如何工作
- 与global有关系吗?
- 要注意点啥
nonlocal的面貌
闪亮登场
让我们从故事开始讲起。
有一个古老的图书馆,每一本书都是一个函数,书架就像是函数的作用域,而 nonlocal 关键词则是一个特殊的通行证,它允许你在一个函数里修改另一个嵌套函数中的变量。
但这不是随随便便就能做的事, nonlocal 声明的是那些既不属于局部作用域,也不属于全局作用域的变量,它们处于嵌套函数的中间地带。
在 Python 的世界里,函数可以嵌套函数,就像盒子套盒子一样。通常情况下,每个盒子(函数)里的东西(变量)只能在自己的盒子里被找到和修改。
但有时候,内层的小盒子想要去改变外层盒子里的某个东西,这时候就需要用到 nonlocal 这个法术了。
nonlocal的本质
nonlocal 的存在像是一条隐形的桥,连接着嵌套函数之间的变量。
要理解 nonlocal ,得先搞清楚Python里的作用域和变量。简单来说,作用域决定了在哪些地方你可以访问哪些变量。(我们马上就会说什么是作用域~)
在Python中,函数就像是一个小盒子,里面定义的变量默认只在盒子里有效,外面是访问不到的。
nonlocal 的魅力在于它提供了一种微妙的方式来修改嵌套作用域中的变量。
这在编写闭包或者装饰器等高级功能时特别有用。它让变量的作用域既不是那么封闭也不是无限开放,而是在一个合适的层级中进行操作。
nonlocal多了解一点
必须在外层非全局作用域中定义
nonlocal 关键字的一个核心特性是,它声明的变量必须已经存在于外层函数的作用域中,而不能是全局作用域或当前作用域中新定义的。
这就像是在一个家族聚会中,你只能通过 nonlocal 声明去引用那些已经到场的家族成员(变量),而不是那些根本没来(未定义)或者是全家族都知道的大名人物(全局变量)。
不能用于全局变量或最外层函数
nonlocal 的设计初衷是为了解决嵌套函数间变量共享的问题,而全局变量本来就对所有函数可见,没有必要用 nonlocal 来声明。
如果你试图在最外层函数中使用 nonlocal 声明变量,Python 会抛出一个语法错误,因为 nonlocal 需要一个封闭的函数作用域来寻找相应的变量,而最外层函数没有“外层”了。
def outer_function():
nonlocal x
x = 10
outer_function()
报错信息:
SyntaxError: no binding for nonlocal 'x' found
适用于多层嵌套场景
nonlocal 在多层嵌套的函数场景下显得尤为重要。在这种情况下,如果内层函数需要修改外层函数(但不是全局作用域)中定义的变量, nonlocal 就能派上用场。
nonlocal 促成了一种在函数间共享变量的机制,这大大增强了函数内部的互动性和灵活性。
通过这种方式,嵌套函数不再是孤立的个体,而是能够相互影响和协作,共同完成更复杂的任务。
def outer_function():
shared_variable = 0
def inner_function1():
nonlocal shared_variable
shared_variable += 1
print("Inner Function 1: shared_variable =", shared_variable)
def inner_function2():
nonlocal shared_variable
shared_variable += 2
print("Inner Function 2: shared_variable =", shared_variable)
inner_function1()
inner_function2()
print("Outer Function: shared_variable =", shared_variable)
outer_function()
输出:
Inner Function 1: shared_variable = 1
Inner Function 2: shared_variable = 3
Outer Function: shared_variable = 3
nonlocal如何工作
来看一个简单的例子:
pythonCopy codedef outer():
x = "local"
def inner():
nonlocal x # 这里我们使用 nonlocal 关键字
x = " nonlocal "
print("内部:", x)
inner()
print("外部:", x)
outer()
在这个例子中,inner 函数中的 nonlocal 声明允许我们修改 outer 函数中的 x 变量。
当我们调用 outer 函数时,它首先设置 x 为 “local” ,然后调用 inner函数。
inner 函数中的nonlocal x
声明意味着当我们在 inner 中改变 x
的值时,实际上是在改变outer
函数作用域中的x
。
因此,输出会是:
内部: nonlocal
外部: nonlocal
与隔壁的global聊聊
nonlocal与global的区别
简单来说, global用于在局部作用域中修改全局变量,而 nonlocal 则用于修改嵌套作用域中的变量。
如果Python是一个国度,那么 global 就像是国王的法令,可以在任何地方发挥作用;
而 nonlocal 更像是一个地方领主的权力,它只在自己的领地内有效。
global 的魔法
global 关键字用来在函数或其他局部作用域中声明全局变量。
x = "这是全局的"
def my_function():
global x # 使用 global 关键字声明
x = "全局变量被修改了"
my_function()
print(x) # 输出: "全局变量被修改了"
nonlocal的巫术
nonlocal 关键字的作用则更为精细。它用于嵌套函数中,允许你修改外层函数(非全局作用域)中的变量。
def outer():
y = "外层变量"
def inner():
nonlocal y # 使用 nonlocal 关键字声明
y = "外层变量被修改了"
inner()
print(y) # 输出: "外层变量被修改了"
outer()
使用nonlocal的注意点
明确存在的变量
nonlocal 声明的变量必须已经在外层函数的作用域中存在。
这就像你不能指派一个不存在的人去完成任务一样。
非全局作用域
nonlocal 不能用于全局变量或在包含 nonlocal 声明的最外层函数中。
它专门设计用来在嵌套函数之间共享变量。
避免混淆
在使用 nonlocal 时,要确保你没有在同一作用域内重新定义相同名称的变量,这会引起混淆并可能导致不可预料的结果。
这就像在一个房间里不能有两个完全相同的标识,以免造成混淆。
不要过度使用
虽然 nonlocal 提供了一种修改外层变量的便捷方式,但过度使用可能会使代码变得难以理解和维护,特别是在复杂的嵌套函数中。
每次使用 nonlocal 时,都要考虑是否有更简单的设计或方法可以达到同样的目的。
是否推荐使用 nonlocal
nonlocal 的使用取决于具体的编程需求和场景。
在某些情况下,如闭包或装饰器等高级编程模式中, nonlocal 是实现特定功能的必要工具。在这些场景下, nonlocal 的使用是推荐的,因为它提供了一种优雅的解决方案。
然而,如果可以通过更简单的设计达到同样的目的,比如使用类(面向对象编程)来管理状态,那么优先考虑这些方法可能更佳。
过度或不恰当地使用 nonlocal 可能会使代码难以理解和维护,特别是对于不熟悉嵌套作用域概念的新手来说。