python - Python 中的变量范围和名称解析

标签 python scope

我认为我从根本上不理解Python是如何做变量作用域和名称解析之类的事情的。特别是,下面的函数 broken() 不起作用这一事实确实让我感到惊讶。而且,尽管我在网上搜寻了一段时间寻找有用的解释,但我仍然不明白。任何人都可以解释或链接到关于这些东西在 Python 中如何工作的详细描述,并提供足够的详细信息,以便在阅读相关 Material 后可以清楚地看出为什么 broken() 不起作用?

# Why does this code work fine
def okay0():
    def foo():
        L = []
        def bar():
            L.append(5)
        bar()
        return L
    foo()

# and so does this
def okay1():
    def foo():
        def bar():
            L.append(5)
        L = []
        bar()
        return L
    foo()

# but the following code raises an exception?
def broken():
    def foo():
        L = []
        bar()
        return L
    def bar():
        L.append(5)
    foo()

# Example
test_list = [okay0, okay1, broken]
for test_function in test_list:
    try:
        test_function()
    except:
        print("broken")
    else:
        print("okay")

最佳答案

在另一个函数中定义的函数可以访问其父级的作用域。

在您的具体情况下,L 始终在 foo() 中定义。在前两个示例中,bar() 也在 foo() 中定义,因此它可以通过上述规则访问 L(即,foo()bar() 的父级)。

但是,在 broken() 上,bar()foo() 是 sibling 。他们对彼此的作用域一无所知,因此 bar() 无法看到 L

来自documentation :

Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible:

  • the innermost scope, which is searched first, contains the local names
  • the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
  • the next-to-last scope contains the current module’s global names
  • the outermost scope (searched last) is the namespace containing built-in names

现在,如果 Lbar() 之后以文本方式定义,为什么 okay1 可以工作?

Python 在必须实际运行代码之前不会尝试解析标识符(动态绑定(bind),如 @Giusti 的回答中所述)。

当 Python 执行该函数时,它会看到一个标识符 L 并在本地命名空间中查找它。在 cpython 实现上,它是一个实际的字典,因此它在字典中查找名为 L 的键。

如果没有找到,它会检查任何封闭函数的范围,即代表封闭函数的本地命名空间的其他字典。

请注意,即使 Lbar() 之后定义,当 bar() 为 < em>称为,L已被定义。所以,当执行bar()时,L已经存在于foo()的本地命名空间中,当Python看不到时会搜索该命名空间bar() 内的 L

文档的支持部分:

A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries, but that’s normally not noticeable in any way (except for performance), and it may change in the future.

(...)

The local namespace for a function is created when the function is called, and deleted when the function returns or raises an exception that is not handled within the function. (Actually, forgetting would be a better way to describe what actually happens.) Of course, recursive invocations each have their own local namespace.

A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.

关于python - Python 中的变量范围和名称解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57797690/

相关文章:

python - sqlalchemy 中的多个/拆分类关联

python - pyspark 中的主 URL 是什么?

python - 为什么我不能使用带星号的表达式?

javascript - 从回调中访问 `this`

c - 当字符串位于数组中时,如何从函数返回字符串

scala - 在 Scala 中,我如何显式引用封闭的本地范围?

groovy - 用于定义关系的常规静态 block

python - Django 管理列表显示 + ForeignKey = 空更改列表

c++ - decltype 和隐藏外部名称的类成员名称之间的交互

python - 如何在按下按钮后更改 TextInput 文本