为什么类定义总是生成相同的字节码?

usu*_* me 13 python bytecode disassembly python-internals

说我同意:

#!/usr/bin/env python
# encoding: utf-8

class A(object):
    pass
Run Code Online (Sandbox Code Playgroud)

现在我拆开它:

python -m dis test0.py 
  4           0 LOAD_CONST               0 ('A')
              3 LOAD_NAME                0 (object)
              6 BUILD_TUPLE              1
              9 LOAD_CONST               1 (<code object A at 0x1004ebb30, file "test0.py", line 4>)
             12 MAKE_FUNCTION            0
             15 CALL_FUNCTION            0
             18 BUILD_CLASS         
             19 STORE_NAME               1 (A)
             22 LOAD_CONST               2 (None)
             25 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

现在我在类定义中添加一些语句:

#!/usr/bin/env python
# encoding: utf-8

class A(object):
    print 'hello'
    1+1
    pass
Run Code Online (Sandbox Code Playgroud)

然后我又拆开了:

  4           0 LOAD_CONST               0 ('A')
              3 LOAD_NAME                0 (object)
              6 BUILD_TUPLE              1
              9 LOAD_CONST               1 (<code object A at 0x1004ebb30, file "test0.py", line 4>)
             12 MAKE_FUNCTION            0
             15 CALL_FUNCTION            0
             18 BUILD_CLASS         
             19 STORE_NAME               1 (A)
             22 LOAD_CONST               2 (None)
             25 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

新语句中出现的新语句不是什么?

Mar*_*ers 17

新语句存储在嵌套字节码中.您可以在反汇编中看到加载了另一个代码对象:

      9 LOAD_CONST               1 (<code object A at 0x1004ebb30, file "test0.py", line 4>)
Run Code Online (Sandbox Code Playgroud)

您需要检查代码对象.这是因为类主体就像一个函数对象一样执行,然后调用产生的本地命名空间用于形成类成员.

演示:

>>> import dis
>>> def wrapper():
...     class A(object):
...         pass
... 
>>> dis.dis(wrapper)
  2           0 LOAD_CONST               1 ('A')
              3 LOAD_GLOBAL              0 (object)
              6 BUILD_TUPLE              1
              9 LOAD_CONST               2 (<code object A at 0x104b99930, file "<stdin>", line 2>)
             12 MAKE_FUNCTION            0
             15 CALL_FUNCTION            0
             18 BUILD_CLASS         
             19 STORE_FAST               0 (A)
             22 LOAD_CONST               0 (None)
             25 RETURN_VALUE        
>>> dis.dis(wrapper.__code__.co_consts[2])
  2           0 LOAD_NAME                0 (__name__)
              3 STORE_NAME               1 (__module__)

  3           6 LOAD_LOCALS         
              7 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

这与您的第一个样本设置相同; 通过wrapper.__code__.co_consts元组访问类主体,这是LOAD_CONST字节代码所指的内容; 索引为2.

现在我们可以添加一个类体:

>>> def wrapper():
...     class A(object):
...         print 'hello'
...         1+1
...         pass
... 
>>> dis.dis(wrapper)
  2           0 LOAD_CONST               1 ('A')
              3 LOAD_GLOBAL              0 (object)
              6 BUILD_TUPLE              1
              9 LOAD_CONST               2 (<code object A at 0x104b4adb0, file "<stdin>", line 2>)
             12 MAKE_FUNCTION            0
             15 CALL_FUNCTION            0
             18 BUILD_CLASS         
             19 STORE_FAST               0 (A)
             22 LOAD_CONST               0 (None)
             25 RETURN_VALUE        
>>> dis.dis(wrapper.__code__.co_consts[2])
  2           0 LOAD_NAME                0 (__name__)
              3 STORE_NAME               1 (__module__)

  3           6 LOAD_CONST               0 ('hello')
              9 PRINT_ITEM          
             10 PRINT_NEWLINE       

  4          11 LOAD_CONST               2 (2)
             14 POP_TOP             

  5          15 LOAD_LOCALS         
             16 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

现在出现了班级的身体; 我们可以看到在加载类主体时将执行的字节代码.

值得注意的是为每个类体执行的字节码LOAD_NAMESTORE_NAME字节码; 那些检索模块名称并将它们存储为新的本地名称__module__,以便您的类__module__在创建后最终会得到一个属性.

然后LOAD_LOCALS字节码收集在这个'function'中产生的所有本地名称,并将其返回给调用者,这样BUILD_CLASS字节码就可以将它与'A'字符串一起使用,而object基元tuple(用其创建BUILD_TUPLE)可以产生新的类对象.