首页 新闻 会员 周边 捐助

编译期生成的字节码能重新绑定运行期间的对象?这能在字节码里面体现出来,有指令重新绑定过程?

0
[已关闭问题] 关闭于 2025-09-01 11:05
@contextmanager
def timer():
      start = time.time()
      yield
      end = time.time()
      print(end-start)
这个编译成字节码对象时,将timer代码对象+timer函数名组装成未装饰的函数对象,调用装饰器函数contextmanager(timer),返回一个装饰器函数(自动添加了__enter和__exit)
STORE_NAME 3(timer) 符号表co_names的timer不变,改变运行时的命名空间字典(globals/locals),名字和新对象绑定
这是什么原理?编译期生成的字节码能重新绑定运行期间的对象?这能在字节码里面体现出来,有指令重新绑定过程?
_java_python的主页 _java_python | 小虾三级 | 园豆:984
提问于:2025-09-01 11:04
< >
分享
所有回答(1)
0
字节码里并不会“重新编译”什么,它只是执行了一条普通的 STORE_NAME / STORE_FAST 指令,把一个全新的对象重新写进当前作用域的 dict / fast-locals 槽里。编译期生成的符号表(co_names、co_varnames …)在运行期是只读的;真正可变的是运行时命名空间(PyDictObject 或 fast-locals 数组),字节码里对名字的“重新绑定”就是一次普通的键值覆写。
下面把整个过程拆成三段来说明:
编译期到底生成了哪些“不可变”的东西
• 对源代码里的 def timer(): ...,编译器生成
– 一个 PyCodeObject,里边有字节码、co_names、co_varnames 等;
– 一个 PyFunctionObject(记作 f0),它的 func_code 指向上面的 code,func_globals 指向当时的 globals;
– 然后把 f0 存进当前 locals / globals 的键 "timer" 中(对应字节码 STORE_NAME / STORE_GLOBAL / STORE_FAST,视作用域而定)。
• 对 @contextmanager 这一行,编译器只看到语法糖,于是生成了另一条“装饰器协议”字节码:
复制
LOAD_NAME    contextmanager   # 把装饰器对象推到栈顶
LOAD_NAME    timer            # 把刚才存进去的 f0 再取出来
CALL_FUNCTION 1                # 执行 contextmanager(f0) 得到 f1
STORE_NAME   timer            # 把 f1 重新写回名字 'timer'
注意:这里 co_names 里 "timer" 这个字符串的索引在整个 PyCodeObject 里不会变,变的是运行时 dict 里 "timer" 这个键对应的值。
运行期到底发生了什么
• 模块首次 import 时,Python 虚拟机顺序执行字节码:
– 先执行 def 的 BUILD_FUNCTION/STORE_NAME,此时 locals()['timer'] == f0;
– 再执行装饰器指令序列,contextmanager(f0) 返回一个新的 helper 对象(内部包装了 f0,并添加了 enter/exit);
– 最后执行 STORE_NAME 再次把 locals()['timer'] 改成这个 helper。
• 这条 STORE_NAME 与给普通变量赋值的字节码一模一样,没有任何特殊“重新绑定”指令;只不过这次右值恰好是另一个完全不同的对象。
字节码层面能否看出“重绑定”?
拿 3.11 举例,把模块编译成字节码后反汇编:
复制
  0 LOAD_NAME                0 (contextmanager)
  2 LOAD_NAME                1 (timer)     # 这里 timer 还是 f0
  4 CALL                     1
  6 STORE_NAME               1 (timer)     # 执行后 timer 变成 f1
索引 1 在 co_names 中恒定是字符串 "timer";指令本身只是“把栈顶存到名字 1 对应的位置”。
因此,“重新绑定”完全体现在运行时数据结构的更新,而字节码里只是一条普通的 STORE_NAME(或 STORE_FAST/STORE_GLOBAL,视作用域而定)
_java_python | 园豆:984 (小虾三级) | 2025-09-01 11:04
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册