【随手记】python中的nonlocal关键字

简介: 【随手记】python中的nonlocal关键字

看一段代码,下边这段代码用于将二叉搜索树转换为升序排列的双向链表:

"""
# Definition for a Node.
class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
"""
class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        if not root:
            return root
        # 递归函数,用于中序遍历和连接节点
        def recursion(root):
            nonlocal prev, head
            if root:
                # 递归遍历左子树
                recursion(root.left)
                # 将当前节点与前一个节点连接起来
                if prev:
                    prev.right = root
                    root.left = prev
                else:
                    # 当前节点是最左的节点,将其赋值给head
                    head = root
                prev = root
                # 递归遍历右子树
                recursion(root.right)
        prev = None  # 前一个节点
        head = None  # 头节点
        recursion(root)
        # 将头节点和尾节点连接起来,形成循环双向链表
        head.left = prev
        prev.right = head
        return head

去掉nonlocal,会报错:

UnboundLocalError: cannot access local variable 'prev' where it is not associated with a value

解释:

nonlocal 是Python中的关键字,用于声明一个嵌套函数中的变量是来自于其外部函数的局部作用域,而不是来自于全局作用域。

在这段代码中,prevhead 是在 recursion 函数之外定义的变量。然而,我们需要在 recursion 函数中对它们进行修改。为了在 recursion 函数中能够访问并修改这些变量,我们使用 nonlocal 关键字来声明它们。

这样,在 recursion 函数中对 prevhead 的修改将会影响到它们在 treeToDoublyList 方法中的值。这使得我们能够在 recursion 函数中正确地处理节点的连接和循环链表的生成。

再看下边一段二叉树中序遍历的代码:

class Solution:
    def inorderSearch(self, root: 'Node') -> 'Node':
        if not root:
            return None
        res = []
        def inorder(node):
            if node:
                inorder(node.left)
                res.append(node.val)
                inorder(node.right)
        
        inorder(root)
        return res

res同样是在外层函数中定义然后在内层函数中使用,为什么这里没有加上nonlocal也没有报错?

在这段代码中,res 是一个列表,它是在外层函数 treeToDoublyList 中定义的。在 Python 中,列表是可变对象,可以在函数内部通过引用进行修改。

inorder 函数中,虽然 res 是在外层函数中定义的,但是我们只是对其进行修改,没有重新赋值。因此,Python 会默认将 res 视为外层函数中定义的变量,而不是新的局部变量。

nonlocal 不同,nonlocal 用于改变外层函数的局部变量,而不是修改可变对象的值。因此,在使用 nonlocal 时,我们需要明确告诉 Python 我们要修改的是外层函数的局部变量。而对于可变对象,Python 默认会将其视为外层函数的局部变量,因此不需要使用 nonlocal

总结起来,列表等可变对象可以在函数内部进行修改,而不需要使用 nonlocal;而对于需要修改外层函数的局部变量时,我们需要使用 nonlocal 关键字。

目录
相关文章
|
3月前
|
程序员 Python
【随手记】python中各类下划线的作用与功能
【随手记】python中各类下划线的作用与功能
53 0
|
3月前
|
Python
`try-except-finally`是Python异常处理的关键字,用于优雅地处理错误
【6月更文挑战第22天】`try-except-finally`是Python异常处理的关键字,用于优雅地处理错误。示例展示了函数`divide_numbers(a, b)`尝试执行`a/b`,若出现`ZeroDivisionError`,则捕获异常并打印错误信息,最后不论是否异常,都会显示"Division operation completed."。调用该函数分别展示正常除法和除零错误的处理情况。
42 2
|
3月前
|
人工智能 算法 Python
【随手记】python的heapq库的基本用法
【随手记】python的heapq库的基本用法
51 1
|
2月前
|
Python
|
2月前
|
IDE 开发工具 Python
python语法错误关键字使用错误
【7月更文挑战第9天】
41 6
|
2月前
|
SQL 数据库 开发者
【Python】已解决:pymssql._pymssql.OperationalError 关于关键字‘distinct’的语法错误
【Python】已解决:pymssql._pymssql.OperationalError 关于关键字‘distinct’的语法错误
33 1
|
2月前
|
存储 大数据 Python
Python中的yield关键字是什么?
`yield`是Python的关键字,用于创建生成器,实现懒惰计算。生成器函数在遇到`yield`时暂停并返回值,状态得以保留,下次迭代时从中断点继续。生成器是迭代器的一种,常用于处理大数据集或无限序列,避免一次性加载所有数据。例如,`simple_generator`函数通过`yield`逐次返回1, 2, 3。生成器函数如`fibonacci_generator`可用于生成斐波那契数列,而生成器表达式则提供了一种简洁的生成值方式,如`(x**2 for x in range(1, 6))`生成平方数。`yield`还可用于创建无限序列、过滤值(如只生成偶数)和实现懒惰计算
|
3月前
|
开发者 Python
在Python中,异常处理通过`try`、`except`、`else`和`finally`关键字进行
【6月更文挑战第26天】在Python中,异常处理通过`try`、`except`、`else`和`finally`关键字进行。基本结构包括尝试执行可能抛出异常的代码,然后指定`except`来捕获特定或任何类型的异常。`else`块在`try`无异常时执行,`finally`块确保无论是否发生异常都会执行,例如用于清理。可以使用`raise`重新抛出异常,而自定义异常则允许创建特定的错误类。这种机制增强了代码的健壮性。
54 7
|
3月前
|
存储 Python 容器