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
相关产品推荐
相关产品推荐

