函数内部的Python全局关键字可见性

2024-04-26 18:47:05 发布

您现在位置:Python中文网/ 问答频道 /正文

当我错误地运行CODE1时,我正在检查global关键字在项目中是如何工作的,它的工作方式出乎我的意料。global关键字在函数中生效,即使它不在已执行的部分中(即在if条件为not true时)。你知道吗

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

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

下面,我使用的代码的三个最小可复制示例如下所示:

代码1(带全局关键字):

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

代码2(不带全局关键字):

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(带全局关键字,但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:始终为假,if b==2:始终为真(print证实了这一点)。我希望CODE1给出与CODE2相同的结果,因为在第一个示例中global a不会被执行,所以它与ommiting相同。但是它给出了一个innesperate结果,其中global关键字无论如何都会生效,并且全局变量a的值更改为2。之后,我用CODE3进行了测试,认为global关键字在所有函数中都是可见的,而不管其位置如何,然后CODE3应该给出与CODE1相同的结果。我又错了,它的工作方式就像global a要执行一样(然后是在asignation之后,引发了一个异常)。你知道吗

然后,我的最后一个问题是:?全局关键字(可能还有其他关键字,如nonlocal等)是否在代码中以编写顺序显示,但与执行的内容无关?

请帮我澄清一下。你知道吗


Tags: 代码nameifmainmydeffunction关键字
1条回答
网友
1楼 · 发布于 2024-04-26 18:47:05

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

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

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

Names listed in a global statement must not be used in the same code block textually preceding that global statement.

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

相关问题 更多 >