You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python类创建时NameError问题的成因及不同写法有效性疑问

Python类定义中枚举与列表推导式的作用域问题解析

一、初始代码的NameError原因

初始代码:

from enum import Enum

class A:
    class Numbers(Enum):
        ONE = 1
        TWO = 2
    ODDS = (Numbers.ONE,)
    EVENS = [number for number in Numbers if not number in ODDS]

Python 3的列表推导式拥有独立的局部作用域,无法直接访问类定义作用域中的变量。在定义EVENS的列表推导式里,ODDS是类A的属性,但列表推导式只会查找自身局部作用域和全局作用域,找不到ODDS,因此抛出NameError。

二、使用A.ODDS的结果不符合预期原因

修改后的代码:

from enum import Enum

class A:
    class Numbers(Enum):
        ONE = 1
        TWO = 2
    ODDS = (Numbers.ONE,)
    EVENS = [number for number in Numbers if not number in A.ODDS]

Python执行class A:语句时,会先创建临时类对象,执行完整个class块的代码后,才会将A绑定到这个新类对象。如果之前Shell中已经定义过类A,那么在执行当前class块的过程中,A仍然指向旧的类对象,而非正在创建的新类。此时A.ODDS引用的是旧类的ODDS属性,和新定义的Numbers枚举成员不属于同一类实例,导致number in A.ODDS始终为False,最终EVENS包含所有枚举成员,不符合预期。

三、第三种写法时灵时不灵的原因

再次修改后的代码:

from enum import Enum

class A:
    class Numbers(Enum):
        ONE = 1
        TWO = 2
    ODDS = (Numbers.ONE,)
    EVENS = [number for number in A.Numbers if not number in A.ODDS]
  • 有效场景:如果Shell中之前已经定义过类A,那么在重新定义A的过程中,A仍然指向旧类对象,此时A.Numbers和A.ODDS都能正常访问(引用旧类的属性)。若旧类的ODDS和新定义的ODDS内容一致,就会得到正确结果,但本质是误用了旧类的属性,并非正确引用新类的属性。
  • 无效场景:重启Shell后第一次执行该代码时,A尚未被定义(class块还没执行完,A还未绑定到新类对象),列表推导式中访问A.Numbers和A.ODDS时,会抛出NameError。

内容的提问来源于stack exchange,提问作者Burakhan Aksoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 10:42:53