Python类和全局变量与局部变量

6
我不太理解以下代码的结果是什么:

my_str = "outside func"
def func():
    my_str = "inside func"
    class C():
        print(my_str)
        print((lambda:my_str)())
        my_str = "inside C"
        print(my_str)

输出结果是:
outside func
inside func
inside C

另一段代码是:

my_str = "not in class"
class C:
    my_str = "in the class"
    print([my_str for i in (1,2)])
    print(list(my_str for i in (1,2)))

输出结果为:
[‘in the class’, 'in the class’]
['not in class’, 'not in class’]

问题是:

  1. 每个print()语句中发生了什么?
  2. 有人能解释一下为什么print()语句从不同的命名空间获取字符串吗?

编辑1:

我认为这与这个问题不同,因为我谦虚地认为那里的答案没有解释这种变化:

my_str = "outside func"
def func():
    my_str = "inside func"
    class C():
        print(my_str)
        print((lambda:my_str)())
       #my_str = "inside C"
        print(my_str)

输出为:
inside func
inside func
inside func

编辑2:

的确,这是一个重复问题,来自这个问题,因为正如Martijn Pieters所说:

那里的答案说明:如果在类体内分配了名称,几乎是在开始时。你赋值给了my_str,使它与y相同。注释掉那行意味着你不再分配给my_str,使它与x相同。



@MartijnPieters 在那里给出了关于第一个情况的完美答案。第二种情况会涉及到它,但它并不是完全重复。也许我会将该链接留给将来访问此问题的人。(你已经准备好草稿了,对吧?) - Bhargav Rao
2
@BhargavRao:抱歉,我实际上认为你链接的是Python作用域规则简述!这确实是一个重复问题。 - Martijn Pieters
1个回答

5
这里有四个作用域:
  1. 全局作用域
  2. 函数作用域
  3. 类体
  4. lambda函数作用域
创建一个类声明时,类体会像执行一个函数一样被执行,并且该“函数”的本地命名空间将用作类属性。
但是,类体不是作用域,因此与函数的行为不同。在函数体中,绑定定义了作用域; 在函数中给一个名称赋值,它就标记为局部变量。在类中,给一个名称赋值会使其成为全局变量,直到您实际进行赋值为止。
所以你的第一个`print()`调用发现`my_str`作为全局变量,因为在类体中稍后你将绑定到该名称。这是类体未参与作用域的结果。
接下来,你定义一个 lambda 并调用它。在该 lambda 中没有对 `my_str` 进行赋值,因此必须在父级作用域中找到它。这里类体不是作用域,上一个作用域是函数作用域。这就是为什么那行打印出`inside func`的原因。
最后,在类体中将值赋给局部变量 `my_str`,并打印出该局部变量。
当你移除这个赋值时,类中的名称被视为非局部的。第一个和最后一个`print()`语句现在相等,名称只是根据正常的作用域规则进行查找。

你能否扩展一下你的回答,解释一下Edit1的变化? - Dargor
3
@PabloGalindoSalgado:你的编辑只是确认了这篇帖子是重复的。 - Martijn Pieters
非常抱歉。我已经读了两遍答案,但是还是不理解那个变化……但是就像你说的那样很简单。该喝咖啡了。:( - Dargor
@PabloGalindoSalgado:那里的答案说:如果在类体内分配了一个名称,几乎是在开头。你把my_str赋值给了它,使它与那里的y相同。注释掉那行意味着你不再分配给my_str,使它与x相同。 - Martijn Pieters
今天我没有足够小心。对于造成的混乱,我深表歉意和道歉。 - Dargor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接