【随手记】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 关键字。

你可能感兴趣的:(随手记,python,python,开发语言)