Python类继承报NameError:子类先于父类定义的报错原因解析
先看你遇到的具体情况:
你最初编写的代码是这样的:
class A(B): def display(self): print ("In A") class B: def display(self): print ("In B")
运行时直接抛出错误:
Traceback (most recent call last):
File "/Users/praveen/Documents/test.py", line 1, in
class A(B):
NameError: name 'B' is not defined
但把父类B的定义放到子类A前面后,代码就能正常运行:
class B: def display(self): print ("In B") class A(B): def display(self): print ("In A")
核心原因:Python是从上到下逐行执行的,类定义也不例外
当Python执行到class A(B):这一行时,它需要立刻确认括号里的B是什么——但这时候B的定义还在代码的后半段,Python根本还没读到它,自然会判定B是一个未定义的名字,直接抛出NameError。
你可能会好奇为什么有些语言允许先写子类再写父类?那是因为这类语言有预编译阶段,会先扫描所有类定义再执行代码。但Python是解释型语言,没有预编译步骤,代码是边读边执行的,不存在"提前知道后面有什么"的情况。
再拆解下类定义的执行逻辑
当Python处理class X(...)语法时,会先计算括号里的父类表达式——也就是这里的B。这一步是实时的:如果当前作用域里还没有B这个对象(也就是还没执行到class B:那一行),Python就找不到这个名字,报错是必然的。
而当你把B的定义放到前面,Python会先执行class B:,把B这个类对象注册到当前作用域中。之后再执行class A(B):时,就能顺利找到B的定义,完成子类A的创建。
补充个小细节:函数内的类也遵循同样规则
哪怕是在函数内部定义类,顺序要求也完全一致——父类必须在子类定义前已经被执行过,否则一样报错。比如下面这段代码也会触发NameError:
def create_classes(): class C(D): pass class D: pass create_classes()
把D放到C前面就能正常运行。
总结一下:Python的代码执行顺序是严格从上到下,类定义时要求父类已经存在于当前作用域,所以一定要把父类的定义写在子类前面。
内容的提问来源于stack exchange,提问作者praveen

