【问题标题】:Python global keyword visibility inside function函数内部的 Python 全局关键字可见性
【发布时间】:2019-10-28 14:01:07
【问题描述】:

当我错误地运行 CODE1 时,我正在检查项目的全局关键字是如何工作的,它的工作方式出乎我的意料。 global 关键字在函数中生效,即使它不在执行部分中(即在 if 中哪个条件不成立)。

我一直在寻找有关 python 中 global 关键字的问题,但我找不到对此的回应。我看到了:Python global keyword behaviorglobal keyword in pythonUsing global variables in a function

最有趣的,我认为可能与它有关的是这个(但我不确定):Python global keyword

下面显示了我使用的代码的三个最小可重现示例:

CODE1(带全局关键字):

a = 0
def my_function():
    b=2
    if b==0:
        print("first if")
        global a
    if b==2:
        print("second if")
        a = 2
        print("func -> a", a)
        print("func -> b", b)

if __name__ == '__main__':
    my_function()
    print("main -> a", a)

结果:

second if
func -> a 2
func -> b 2
main -> a 2

CODE2(无全局关键字):

a = 0
def my_function():
    b=2
    if b==0:
        print("first if")
    if b==2:
        print("second if")
        a = 2
        print("func -> a", a)
        print("func -> b", b)

if __name__ == '__main__':
    my_function()
    print("main -> a", a)

结果:

second if
func -> a 2
func -> b 2
main -> a 0

CODE3(使用 global 关键字,但反转 if 语句):

a = 0
def my_function():
    b=2
    if b==2:
        print("second if")
        a = 2
        print("func -> a", a)
        print("func -> b", b)
    if b==0:
        print("first if")
        global a

if __name__ == '__main__':
    my_function()
    print("main -> a", a)

结果:

  File "global_var_test.py", line 18
    global a
    ^
SyntaxError: name 'a' is used prior to global declaration

可以看出,if b==0: 始终为 False,if b==2: 始终为 True(打印确认)。我希望 CODE1 给出与 CODE2 相同的结果,因为global a 不会在第一个示例中执行,因此与省略它相同。但它给出了一个无关紧要的结果,其中 global 关键字无论如何都会生效,并且全局变量 a 更改为值 2。在此之后,我用 CODE3 进行了测试,认为 global 关键字在所有函数中都是可见的,无论其位置如何,并且那么 CODE3 应该给出与 CODE1 相同的结果。我又错了,它的工作方式就像 global a 将被执行(然后是在分配之后并引发异常)。

然后,我的最后一个问题是:¿是否使用 global 关键字(可能还有其他诸如 nonlocal 等)在代码中具有可见性,按编写顺序但独立于什么正在执行吗?

请帮我澄清一下。

【问题讨论】:

  • 解析整个函数,并在生成任何代码之前为所有变量确定存储类型(全局/本地/非本地)。 (它必须是这样的,因为存储类型改变了变量访问的执行方式。)所以是的,global 声明,或者在函数中分配变量的事实,可以有函数前面的效果。
  • 另一个例子是当你试图读取一个全局变量,但后来在同一个函数中赋值给它而不声明它是全局的。

标签: python global visibility keyword


【解决方案1】:

我的answer on this question 可能有助于理解这里的一些技术细节,尽管这是一个略有不同的问题。

简而言之,正如您所发现的,Python 编译器基本上会根据变量在函数中的第一次使用方式来确定变量的范围;这与控制语句之类的细节无关,因此如果在看到global语句之前碰巧遇到了a = 2之类的赋值,它将确定a是一个局部变量。如果您尝试反转代码(您没有给出一个非常像这样的示例),以便编译器碰巧看到 global 语句 first 它将起作用(尽管仍然是错误的代码):

a = 0
def my_function():
    b=2
    if b==2:
        print("second if")
        global a
        print("func -> a", a)
        print("func -> b", b)
    if b==0:
        print("first if")
        a = 2

因此,出于实用/技术以及文体目的,您应该始终在函数开头声明global(或nonlocal)变量,而不是其他任何地方。

我不确定这是语言要求还是 CPython 的细节;这将是一个有趣的后续问题。

更新:是的,这是语言规范要求;见https://docs.python.org/3/reference/simple_stmts.html#grammar-token-global-stmt

global 语句中列出的名称不得用于同一代码块中在文本之前该全局语句。

这里textually before仅仅意味着代码的文本,而不考虑控制语句等周围的细节。这是因为global 实际上是对解析器 的一个指令,它根据变量第一次看到使用该变量的方式来确定该变量是否具有本地或全局绑定。尽管在实现细节方面可能仍然不完全准确;例如CPython builds a symbol table 用于代码模块,作为解析器返回的 AST 的单独传递。因此,代码的文本顺序也会影响 AST 中节点的遍历顺序。例如。您可以在the visitor for global statements 中查看错误消息的来源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2022-08-02
    • 2011-11-17
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    相关资源
    最近更新 更多