即使在递归调用中,“非本地”变量是不是总是从外部循环继承?

Posted

技术标签:

【中文标题】即使在递归调用中,“非本地”变量是不是总是从外部循环继承?【英文标题】:Does 'nonlocal' variable always inherit from the outer loop, even in recursive calls?即使在递归调用中,“非本地”变量是否总是从外部循环继承? 【发布时间】:2021-09-23 09:02:15 【问题描述】:

我已经编写了一些代码,最近在编写函数的函数时遇到了“非本地”的需求(在处理递归时遇到了这个问题)。

例如:

def swapPairs(head): 
    head = None

    def helper(node): 
        nonlocal head 
        ...
        head= nex.next 
        return helper(node.next) 

我的问题很简单,因为我们调用递归函数 helper(node.next) ,然后循环回到 nonlocal head - head 的值是否为 None (由于非本地头)?或者它是否保留了在之前的递归调用中分配给它的head = nex.next

所以我想了解'nonlocal head' 是否会导致head 总是取其在外部函数中分配的值,还是不是这种情况?相反,它只是一种在内部函数中初始化 head 的方法,因此它只能通过获取外部函数中定义的初始值来开始。

【问题讨论】:

【参考方案1】:

nonlocalglobal 声明用于词法 作用域——松散地说,它们只关心源代码布局。

def swapPairs(head): 
    head = None         # `head` in lexically outer scope          <═╗
                        #                                            ║
    def helper(node):   #                                            ║
        nonlocal head   # nonlocal `head` for inner lexical scope  >═╣
        ...             #                                            ║
        head= nex.next  # nonlocal applies to every use            >═╝
        return helper(node.next)

值得注意的是,作用域与代码的运行时嵌套无关;它不关心helper 是否被swapPairshelpers 的序列或一些不相关的函数调用:helper 内部的名称head 完全等同于swapPairs 内部的名称head .

这意味着def helper 中的head始终 引用定义def helperswapPairs 调用中的head。一旦对helper 的第一次调用分配了head = nex.next,这将更改head 内的swapPairs,随后对helper 的调用将看到(并修改)这个新值。

【讨论】:

谢谢先生,很好的解释。但为了确认我理解正确,当我们在第一次递归调用时调用 helper(node.next) 时说,当我们运行 helper() 函数时,head=nex.next 而不是 head=None。这是正确的吗? 我确实理解您所说的“def helper 中的 head 将始终引用 swapPairs 中的 head” - 但是,在 swapPairs 中第一次调用 head=None 之后,我们不会访问/调用swapPairs 了。所以我想确认 head=None 永远不会到达。 @PatrickChong 实际上,除非helper(或捕获head 的任何其他函数)分配head = None,否则它不会返回NoneswapPairs 中的 head = None 仍然只是一个按常规顺序执行的常规语句,以后不会隐式重新运行。

以上是关于即使在递归调用中,“非本地”变量是不是总是从外部循环继承?的主要内容,如果未能解决你的问题,请参考以下文章

c语言练习题

c++循环链表的递归基本情况

Java学习之理解递归

static 很好用 (php)

Gradle 总是从最后一种风格中的 buildType 中获取值

即使只有主函数,在主函数外部声明变量也会改变输出