# === 编译阶段 ===
class_body_code = compile("""
print('aaa')
x = 1
def foo(self): pass
""", '<class-body>', 'exec')
# === 运行时 ===
# 1. 造一个“匿名函数”
anonymous_func = MAKE_FUNCTION(class_body_code)
# 2. 调用内置工厂 __build_class__
Student = __build_class__(
func = anonymous_func, # 类体要执行的代码
name = 'Student', # 类名
bases = (), # 基类元组
kwds = None # 关键字参数(元类等)
)
# 3. 工厂内部做的事(简化)
def __build_class__(func, name, bases, **kw):
namespace = {} # 新建类命名空间
func(namespace) # 执行类体,把变量写进 namespace
#func(namespace)
只把 方法体字节码 封装成新的函数对象并塞进 namespace
,不会立即执行方法体。
真正的方法体执行要等到 实例调用 时才会触发。
cls = type(name, bases, namespace) # 构造真正的类对象
return cls
MAKE_FUNCTION → CALL_FUNCTION → __build_class__ → 执行类体 → 返回 Student(类对象)
。class Student: print('aaa') x = 1
print('aaa')
、x = 1
这些语句。__build_class__(匿名函数, 'Student', ())
'Student'
()
__build_class__
内部会 执行匿名函数,于是类体里的代码(print('aaa')
、属性赋值、方法定义)立即跑完,最终返回一个新的 类对象。__build_class__
负责收尾。dis.dis()
直接反编译 类体代码对象 即可,这就是 func(namespace)
真实跑的字节码import dis, types
# 1. 编译类体
source = '''
class Student:
print("aaaaaaaaa")
x = 1
def foo(self): pass
'''
module_code = compile(source, '<string>', 'exec')
# 2. 取出类体代码对象(即 __build_class__ 要调用的 func)
class_body_code = module_code.co_consts[1] # 第 1 个常量就是类体
# 3. 反编译
dis.dis(class_body_code)生成的字节码这就是 func(namespace)
在字节码层跑的全部操作。