第五十九讲问答题第六题求助
6. 请看下面代码,如果调用 test() 函数,那么打印的值分别是什么呢?>>> x = 1
>>> def test():
... x = 2
... print(x)
...
... class C:
... x = 3
... print(x)
...
... def m1(self):
... print(x)
... print(self.x)
...
... def m2(self):
... x = 4
... print(x)
... self.x = 5
...
... def m3(self):
... print(x)
... print(self.x)
...
... c = C()
... c.m1()
... c.m2()
... c.m3()
答案是>>> test()
2
3
2
3
4
2
5
不懂第二个数字到第四个数字为什么是这三个
解析是在类中定义类属性(x = 3),并不会被类方法 m1() 直接通过变量名访问到,所以,在 m1() 中,print(x) 打印的 x 值是 2,print(self.x) 才打印 3(它逻辑上是先去找对象是否有 x 属性,如果没有设置,才去找类属性);但是看不懂,以及怎么和LEGB联系起来 在 Python 中,变量的查找遵循 LEGB 规则:Local、Enclosing、Global、Built-in。这意味着在不同的作用域中,Python 以这个顺序查找变量。
来分析 `test()` 函数执行时每个步骤的变量查找过程:
1. **`print(x)`(函数 `test` 内)**
- `test` 函数的 `local` 作用域中有 `x=2`,因此输出 `2`。
2. **`print(x)`(类 `C` 中)**
- `C` 类定义时,`x=3` 是类作用域中的变量。
- 当类 `C` 被加载时,`print(x)` 查找到的是类作用域中的 `x=3`,因此输出 `3`。
3. **`m1` 方法中的 `print(x)`**
- 方法 `m1` 中的 `x` 查找遵循 LEGB 规则:
- Local: `m1` 方法内没有 `x`。
- Enclosing: `C` 类内没有 `x`,但是 `test` 函数的 `local` 作用域有 `x=2`。
- 因此,`print(x)` 输出 `2`。
4. **`m1` 方法中的 `print(self.x)`**
- `self.x` 是访问对象的属性。
- 因为 `c = C()`,`c` 没有 `x` 的实例变量,所以查找类属性,类 `C` 拥有 `x=3`。
- 因此,`print(self.x)` 输出 `3`。
5. **`m2` 方法中的 `print(x)`**
- `m2` 方法内 `x=4` 是局部变量。
- 因此,`print(x)` 输出 `4`。
6. **`m3` 方法中的 `print(x)`**
- `m3` 方法与 `m1` 方法类似:
- Local: `m3` 方法内没有 `x`。
- Enclosing: `test` 函数的 `local` 作用域中有 `x=2`。
- 因此,`print(x)` 输出 `2`。
7. **`m3` 方法中的 `print(self.x)`**
- 在 `m2` 方法中执行 `self.x = 5`,这为对象 `c` 增加了一个实例变量 `x`。
- 因此,`print(self.x)` 输出 `5`。
希望这个解释能帮助你更好地理解代码运行的过程以及 LEGB 规则是如何应用的!如果有进一步问题,欢迎继续提问!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 LEGB规则是Python中变量查找的顺序规则,用于确定在何处查找变量名。LEGB规则的各个字母代表不同的作用域层次:
;Local(L):局部作用域,指函数内部定义的变量。局部作用域是最近的查找层次,只有在函数内部才能访问到这些变量
Enclosing(E):嵌套作用域,指外部嵌套函数中的变量。如果局部作用域中没有找到变量,解释器会继续在外部嵌套函数的局部作用域中查找
Global(G):全局作用域,指模块层级定义的变量。如果前两个作用域中没有找到变量,解释器会在模块层级的作用域中查找
Builtin(B):内置作用域,指Python内置的名称空间。如果前三个作用域中没有找到变量,解释器会在Python的内置名称空间中查找
第二个数:C类定义时,x=3是类作用域中的变量。
- 当类 C被加载时,print(x) 查找到的是类作用域中的 x=3,因此输出 3。
也就是一被加载就输出了
第三个数:m1方法中的 print(x)
- 方法 `m1` 中的 `x` 查找遵循 LEGB 规则:
- Local: `m1` 方法内没有 `x`。
- Enclosing: `C` 类内没有 `x`,但是 `test` 函数的 `local` 作用域有 `x=2`。
- 因此,`print(x)` 输出 `2`。
print(x) 打印的 x 值是 2,print(self.x) 才打印 3。因为x只是一个变量,不是属性
第四个数:
加了self就是属性
- `self.x` 是访问对象的属性。
- 因为 `c = C()`,`c` 没有 `x` 的实例变量,所以查找类属性,类 `C` 拥有 `x=3`。
- 因此,`print(self.x)` 输出 `3`。
(它逻辑上是先去找对象是否有 x 属性,如果没有设置,才去找类属性)
某一个“天” 发表于 2025-1-11 19:02
LEGB规则是Python中变量查找的顺序规则,用于确定在何处查找变量名。LEGB规则的各个字母代表不同的作用域层 ...
第三个数:m1方法中的 print(x)
- 方法 `m1` 中的 `x` 查找遵循 LEGB 规则:
- Local: `m1` 方法内没有 `x`。
- Enclosing: `C` 类内没有 `x`,但是 `test` 函数的 `local` 作用域有 `x=2`。
- 因此,`print(x)` 输出 `2`。
这里Enclosing说C类没有x,是说class C下的定义是属性x,不是变量x么,
当类 C被加载时,print(x) 查找到的是类作用域中的 x=3,因此输出 3。
那为什么这里还是可以被Print呢? FishC 发表于 2025-1-11 18:14
在 Python 中,变量的查找遵循 LEGB 规则:Local、Enclosing、Global、Built-in。这意味着在不同的作用域中 ...
第三个数:m1方法中的 print(x)
- 方法 `m1` 中的 `x` 查找遵循 LEGB 规则:
- Local: `m1` 方法内没有 `x`。
- Enclosing: `C` 类内没有 `x`,但是 `test` 函数的 `local` 作用域有 `x=2`。
- 因此,`print(x)` 输出 `2`。
这里Enclosing说C类没有x,是说class C下的定义是属性x,不是变量x么,
当类 C被加载时,print(x) 查找到的是类作用域中的 x=3,因此输出 3。
那为什么这里还是可以被Print呢? cindyber 发表于 2025-01-11 22:04
FishC 发表于 2025-1-11 18:14
在 Python 中,变量的 ...
在 Python 中,类定义时的类变量(如 `x=3`)可以被视作类属性,而不是函数内的局部变量。这是因为类的定义本身提供一个新的命名空间。
### 关于 `C` 类中 `print(x)` 输出 `3` 的原因:
- 当类 `C` 被定义时,`x=3` 就在类的命名空间内被绑定。因此在 `C` 的类体内,可以直接访问 `x`,输出为 `3`。
### 关于 `m1` 方法中 `print(x)` 输出 `2` 的原因:
- 对于 `m1` 方法,变量 `x` 的查找遵循 LEGB 规则:
- **Local**: `m1` 内部没有定义 `x`。
- **Enclosing**: `C` 类中定义的 `x` 作为类属性,而不是方法的局部变量,所以这里不被视作 Enclosing 作用域适用。
- **Global**: `test` 函数中的局部变量 `x=2` 由于是 enclosing function 的变量,所以被应用到 `m1`。
- 因此,`print(x)` 输出 `2`,是来自 `test()` 的函数局部变量。
在类的定义体内(比如直接在类中,不是在方法内)可以直接访问和打印类属性,就像在 `C` 类的定义时直接 `print(x)` 会输出 `3`。而在方法内部,并没有直接被访问到(比如 `m1`),LEGB 的规则更为细致,方法内的 `self.x` 用来访问实例属性或类属性。
希望这些解释能够澄清你的疑惑!如果有其他问题,请随时提问。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页:
[1]