首页 新闻 会员 周边 捐助

类也用MAKE_FUNCTION ,CALL_FUNCTION这是为啥,类也能执行?

0
[已解决问题] 解决于 2025-08-28 09:55
伪代码版:把“定义类”拆成 3 步,一目了然。
Python
复制
# === 编译阶段 ===
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(类对象)
_java_python的主页 _java_python | 小虾三级 | 园豆:984
提问于:2025-08-28 09:52
< >
分享
最佳答案
0
你把它当成“先造一个函数,再立刻执行它来生成类对象”就能秒懂。
  1. 类体就是一段普通函数
    编译器把
    Python
    复制
    class Student: print('aaa') x = 1
     
    翻译成 一个匿名函数,函数体就是 print('aaa')x = 1 这些语句。
  2. MAKE_FUNCTION 0
    把这匿名函数包装成 可调用对象。
  3. CALL_FUNCTION 3
    调用 __build_class__(匿名函数, 'Student', ())
    • 第 1 个实参:刚才的匿名函数(类体)
    • 第 2 个实参:类名 'Student'
    • 第 3 个实参:基类元组 ()
    __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) 在字节码层跑的全部操作。

 

_java_python | 小虾三级 |园豆:984 | 2025-08-28 09:54
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册