鱼C论坛

 找回密码
 立即注册
查看: 51|回复: 5

[已解决]第五十九讲问答题第六题求助

[复制链接]
发表于 昨天 18:14 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
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联系起来
最佳答案
昨天 22:04
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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 昨天 18:14 | 显示全部楼层
在 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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 19:02 | 显示全部楼层
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 属性,如果没有设置,才去找类属性)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 22:03 | 显示全部楼层
某一个“天” 发表于 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呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 22:04 | 显示全部楼层
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呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 22:04 | 显示全部楼层    本楼为最佳答案   
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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-12 09:38

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表