0

0

Python nonlocal关键字使用指南:何时以及为何需要它

霞舞

霞舞

发布时间:2025-11-22 12:00:39

|

467人浏览过

|

来源于php中文网

原创

Python nonlocal关键字使用指南:何时以及为何需要它

nonlocal关键字在python中用于指示一个变量赋值操作应作用于最近的非全局(enclosing)作用域中的变量,而非在当前函数内创建新的局部变量。理解其核心在于区分对变量的“重新赋值”与对可变对象“内容修改”:只有当你想在内层函数中改变外层函数变量所引用的对象时,才需要使用nonlocal。

Python变量作用域与赋值机制

在深入理解nonlocal之前,有必要回顾Python的变量作用域规则。Python遵循LEGB(Local, Enclosing, Global, Built-in)规则来查找变量。当在一个函数内部对一个变量进行赋值时,Python默认会将其视为创建了一个新的局部变量,除非该变量已经被声明为global或nonlocal。

例如:

x = 10 # Global

def outer():
    x = 20 # Enclosing scope for inner()
    y = 30 # Enclosing scope for inner()

    def inner():
        # 如果这里直接 x = 40,会创建一个新的局部变量x
        # 如果这里直接 y = 50,会创建一个新的局部变量y
        print(f"在 inner 中访问 outer 的 x: {x}") # 访问 outer 的 x
        print(f"在 inner 中访问 outer 的 y: {y}") # 访问 outer 的 y
    inner()
    print(f"在 outer 中访问 x: {x}")

在上述inner函数中,如果只是访问x和y,它们会从outer作用域中查找。但如果尝试赋值,例如x = 40,Python会默认在inner函数内部创建一个新的局部变量x,而不会修改outer函数中的x。

nonlocal关键字的作用

nonlocal关键字的引入,正是为了解决在嵌套函数中修改非全局、但又非当前局部作用域变量的需求。它明确告诉Python解释器:当前函数内部对某个变量的赋值操作,不应创建局部变量,而应该修改最近一层包含该变量的非全局作用域中的变量。

立即学习Python免费学习笔记(深入)”;

其语法非常简单:

def outer_function():
    variable_in_outer = initial_value

    def inner_function():
        nonlocal variable_in_outer
        variable_in_outer = new_value # 这会修改 outer_function 中的 variable_in_outer

nonlocal与可变对象内容修改的区别

这是理解nonlocal最核心且最容易混淆的部分。nonlocal仅在你想重新绑定(reassign)一个变量,使其指向一个全新的对象时才需要。如果你只是想修改一个可变对象(如列表、字典、集合)的内容,而该可变对象本身是外层作用域的变量所引用的,那么不需要使用nonlocal。

这是因为,对可变对象内容的修改(例如list.append()、set.add()、dict['key'] = value)并没有改变变量本身所引用的内存地址。变量仍然指向同一个对象,只是该对象内部的状态发生了变化。

示例:不需要nonlocal的情况(修改可变对象内容)

Python开发网站指南 WORD版
Python开发网站指南 WORD版

本文档主要讲述的是Python开发网站指南;HTML是网络的通用语言,一种简单、通用的全置标记语言。它允许网页制作人建立文本与图片相结合的复杂页面,这些页面可以被网上任何其他人浏览到,无论使用的是什么类型的电脑或浏览器 Python和其他程序语言一样,有自身的一套流程控制语句,而且这些语句的语法和其它程序语言类似,都有for, if ,while 类的关键字来表达程序流程。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看

下载
def counter_factory():
    count = [0] # 使用列表作为可变容器

    def increment():
        # 这里没有重新赋值 count,只是修改了 count[0] 的内容
        count[0] += 1
        return count[0]
    return increment

my_counter = counter_factory()
print(my_counter()) # 输出 1
print(my_counter()) # 输出 2

在这个例子中,increment函数修改了count列表的第一个元素。count变量本身(即它引用的列表对象)并没有改变,因此不需要nonlocal。

示例:需要nonlocal的情况(重新赋值变量)

def counter_factory_with_nonlocal():
    count = 0 # 整数是不可变类型

    def increment():
        nonlocal count # 声明 count 为非局部变量
        count += 1 # 重新赋值 count,使其指向一个新的整数对象
        return count
    return increment

my_counter_nl = counter_factory_with_nonlocal()
print(my_counter_nl()) # 输出 1
print(my_counter_nl()) # 输出 2

在这个例子中,count是一个整数,它是不可变类型。count += 1实际上是count = count + 1的简写,这是一个重新赋值操作,它让count变量引用了一个新的整数对象。因此,为了修改outer_function中的count变量,这里必须使用nonlocal。

示例代码分析(Leetcode 210 Course Schedule II)

回到最初的问题代码,该代码是一个解决课程表II问题的DFS实现:

class Solution:
    def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
        res = []
        adjList = defaultdict(list)
        visited = set() # 外层作用域的 visited 集合

        # ... (构建邻接表代码省略) ...

        def dfs(curr, path):
            if curr in visited: # 访问 visited
                return True
            if curr in path:
                return False
            path.add(curr)
            for course in adjList[curr]:
                if not dfs(course, path):
                    return False
            path.remove(curr)
            visited.add(curr) # 修改 visited 的内容
            res.append(curr)
            return True

        # ... (拓扑排序调用代码省略) ...

在dfs函数内部,visited变量被用于:

  1. if curr in visited::访问visited集合的内容。
  2. visited.add(curr):向visited集合中添加元素。

这两个操作都属于对visited所引用的集合对象内容的修改,而不是对visited变量本身的重新赋值(例如visited = new_set())。visited变量始终引用着在findOrder函数中创建的那个set()对象。因此,在这种情况下,不需要使用nonlocal visited。如果添加了nonlocal visited,代码仍然能正常工作,但它是多余的,且可能引起对nonlocal用途的误解。

总结与注意事项

  1. nonlocal用于重新赋值: 只有当你需要在内层函数中,对一个外层(非全局)作用域的变量进行重新赋值,使其指向一个新的对象时,才需要使用nonlocal。
  2. 可变对象内容修改无需nonlocal: 如果外层作用域的变量引用的是一个可变对象(如列表、字典、集合),并且你只是想修改这个可变对象的内容(例如append()、add()、update()等方法),则无需使用nonlocal。
  3. 区分nonlocal与global: nonlocal作用于最近的非全局作用域,而global作用于模块级别的全局作用域。
  4. 清晰性优先: 虽然nonlocal可以实现某些功能,但在设计代码时,应优先考虑清晰性和可维护性。如果过度使用nonlocal导致代码逻辑复杂,可能需要重新考虑设计模式,例如将状态作为参数传递或使用类来封装状态。

通过以上分析,我们可以明确nonlocal关键字的核心作用在于处理嵌套函数中变量的重新绑定,而非可变对象的内容修改,这对于编写清晰、正确的Python代码至关重要。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

755

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

636

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

758

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

618

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1262

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

547

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

577

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

707

2023.08.11

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.9万人学习

Django 教程
Django 教程

共28课时 | 3.1万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号