当前位置: 首页 > 知识库问答 >
问题:

为什么搜索BST时会出现“在封闭范围中定义的局部变量”错误?

冯星阑
2023-03-14

我试图回答以下问题(leetcode链接):

给定二叉搜索树的根节点,返回值介于L和R(包括L和R)之间的所有节点的值之和。二叉搜索树保证具有唯一的值。

这是官方的解决方案

class Solution:

    def rangeSumBST(self, root: TreeNode, L: int, R: int) -> int:

        def dfs(node):

            if node:
                if L <= node.val <= R:
                    self.total += node.val
                if L <= node.val:
                    dfs(node.left)
                if node.val <= R:
                    dfs(node.right)

        self.total = 0
        dfs(root)
        return self.total

solution = Solution()
print(solution.rangeSumBST(root, L, R))

它按预期工作,例如对于以下输入:root=[10,5,15,3,7,null,18],L=7,R=15,输出为32。但是,如果我把它写成一个普通函数而没有class语句,为什么会有错误呢?

def rangeSumBST(root: TreeNode, L: int, R: int) -> int:

    def dfs(node):

        if node:
            if L <= node.val <= R:
                total += node.val
            if L <= node.val:
                dfs(node.left)
            if node.val <= R:
                dfs(node.right)

    total = 0
    dfs(root)
    return total

print(rangeSumBST(root, L, R))

这是错误消息:局部变量“total”在赋值前引用的第75行的封闭范围中定义。。。(pyflakes E)第二段代码看起来几乎相同,但我无法解释为什么解决方案的面向对象风格可以工作,而我在将其作为普通函数编写时出错。“total”变量显然有问题,但是在函数范围外定义的变量不也应该在函数范围内访问吗?

共有2个答案

夏俊杰
2023-03-14

因为一个函数应该只依赖于它的参数,可能还有一些全局变量,而不是它上下文中的局部变量。

totalrangeSumBST函数的上下文中定义,该函数包含调用dfs函数的上下文。但这并不好。

因为如果其他人想使用你的dfs函数而不阅读它的定义,他们永远不会知道他们应该在他们想使用你的函数的任何上下文中定义一个变量totoal,这将使你的函数耦合到它的调用上下文。

这样的东西应该工作:

def rangeSumBST(root: TreeNode, L: int, R: int) -> int:

    def dfs(node, total):
        if node:
            if L <= node.val <= R:
                return total + node.val
            if L <= node.val:
                return dfs(node.left, total)
            if node.val <= R:
                return dfs(node.right, total)

    return dfs(root, 0)
段志
2023-03-14

下面是一个重现问题的最小示例:

def enclosing():
    def inner():
        total += 1

    total = 0
    inner()
    return total

enclosing()

这会引发错误:

----> 3         total += 1
      4 
      5     total = 0

UnboundLocalError: local variable 'total' referenced before assignment

这是非常正常的:Python认为,如果你在函数中的任何地方分配给一个变量,它就是局部的。因此,在内部代码中,总代码被认为是本地的,尽管您没有给它一个值,但您试图增加它,因此出现了错误。顶级函数和全局变量总共也会发生同样的情况。

该方法没有相同的问题,因为self没有为其分配任何内容,您只需更改其total属性的值。

这里的解决方案是告诉Python在封闭范围内查找total,这就是Python 3中引入的nonlocal关键字(请参见PEP 3104):

非局部语句使列出的标识符引用最近封闭范围(不包括全局变量)中以前绑定的变量。这很重要,因为绑定的默认行为是首先搜索本地名称空间。该语句允许封装的代码将变量重新绑定到全局(模块)范围之外的局部范围之外。

与全局语句中列出的名称不同,非局部语句中列出的名称必须引用封闭范围中预先存在的绑定(不能明确确定应在其中创建新绑定的范围)。

def enclosing():
    def inner():
        nonlocal total
        total += 1

    total = 0
    inner()
    return total

enclosing()
# 1
 类似资料:
  • 问题内容: 我是lambda和Java8的新手。我面临以下错误。 封闭范围中定义的局部变量日志必须是final或有效的final 问题答案: 该消息说,到底是什么问题:你的变量 数 必须是最后的(即:携带关键字决赛),也可以有效地最终(即:你只有一个值分配给它 一旦 拉姆达外)。否则,您将无法在lambda语句中使用该变量。 但是,当然,这与您使用 log 冲突。关键是:您不能在lambda内部写

  • 问题内容: 我收到错误提示,就像在主题中一样,请问如何修复…错误在menuItem循环中,在这里我尝试将textArea前景颜色设置为从menuItem中选择的一种:(colors [mi]) 问题答案: 该错误意味着 您不能在内部类中使用局部变量。 要在内部类中使用变量,必须对其进行声明。只要是循环计数器并且不能分配变量,就必须创建一种变通方法来获取可在内部类内部访问的变量中的值: 因此,您的代

  • 我正在写一个程序,我得到这样的结果:“最后的局部变量asd不能被赋值,因为它是在一个封闭类型中定义的”。 我将提供一个示例,它不是来自我的代码,但这也会产生错误。我有一个arraylist,我想以后在按钮之外使用它(如果我在按钮内部定义它,以后就不能使用它了),但是按下按钮应该会给这个arraylist提供值。在本例中,它将“创建一个新的ArrayList”,这将导致同样的问题。

  • 问题内容: 我正在测试下面的代码段,我需要知道如何访问tx或t.hello?它的范围是什么?开发人员是否以这种方式定义变量? 编辑 但是为什么这个片段起作用 问题答案: 您应该区分声明和定义。 在您的情况下,您声明一个class变量,并将其分配给派生自某个类的对象(这是一个匿名类),该对象中包含一些其他内容。 此定义之后的代码仅看到类,它对此一无所知,因为没有它们。 因此,除了反射之外,您不能使用

  • 问题内容: 为什么使用lambda函数来获取值列表i = 4。在调用lambda期间,不存在封闭范围。函数f已经完成工作并返回了控制(变量i不存在)。 问题答案: Python使用闭包捕获对原始变量的引用。这些对象保留对名称的引用,可以通过该引用访问值。这意味着变量在完成后将继续存在。 您可以在lambda对象的元组中内省此闭包;函数具有相同的属性: 这也是列表中 所有 lambda 都引用val

  • 是的,关于这个主题有很多类似的问题,但我想澄清一下官方教程是否应该修改。 在 Oracle Java Tutorial https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html 中, 在副标题“访问封闭作用域的局部变量”下, 它说: 由于这个赋值语句,变量不再是有效的最终变量。因此,Java编译器生成类似于