¿Por qué una definición de clase siempre produce el mismo código de bytes?

Di que lo hago

#!/usr/bin/env python # encoding: utf-8 class A(object): pass 

Ahora lo desmonto:

 python -m dis test0.py 4 0 LOAD_CONST 0 ('A') 3 LOAD_NAME 0 (object) 6 BUILD_TUPLE 1 9 LOAD_CONST 1 () 12 MAKE_FUNCTION 0 15 CALL_FUNCTION 0 18 BUILD_CLASS 19 STORE_NAME 1 (A) 22 LOAD_CONST 2 (None) 25 RETURN_VALUE 

Ahora agrego algunas declaraciones en la definición de la clase:

 #!/usr/bin/env python # encoding: utf-8 class A(object): print 'hello' 1+1 pass 

Y vuelvo a desmontar:

  4 0 LOAD_CONST 0 ('A') 3 LOAD_NAME 0 (object) 6 BUILD_TUPLE 1 9 LOAD_CONST 1 () 12 MAKE_FUNCTION 0 15 CALL_FUNCTION 0 18 BUILD_CLASS 19 STORE_NAME 1 (A) 22 LOAD_CONST 2 (None) 25 RETURN_VALUE 

¿Qué no aparecen las nuevas declaraciones en el nuevo bytecode?

Las nuevas declaraciones se almacenan en un bytecode nested . Puedes ver en tu desensamblaje que otro objeto de código está cargado:

  9 LOAD_CONST 1 () 

Necesitas inspeccionar ese objeto de código en su lugar. Esto se debe a que el cuerpo de la clase se ejecuta como un objeto de función, y el espacio de nombres local que produce la llamada se usa para formar los miembros de la clase.

Manifestación:

 >>> 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 (", 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 

Esta es la misma configuración que su primera muestra; se accede al cuerpo de la clase a través de la wrapper.__code__.co_consts tupla, que es a lo que se refiere el código de byte LOAD_CONST ; el índice se da como 2 .

Ahora podemos añadir un cuerpo de clase:

 >>> 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 (", 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 

Ahora aparece el cuerpo de clase; Podemos ver el código de byte que se ejecutará cuando se cargue el cuerpo de la clase.

Son de destacar los LOAD_NAME STORE_NAME LOAD_NAME y STORE_NAME ejecutados para cada cuerpo de clase; los que recuperan el nombre del módulo y los almacenan como un nuevo nombre local __module__ , de modo que su clase terminará con un atributo __module__ una vez creado.

El bytecode LOAD_LOCALS luego reúne todos los nombres locales producidos en esta 'función' y los devuelve al llamante, de modo que el bytecode BUILD_CLASS puede usar eso junto con la cadena 'A' y la tupla de bases de object (creada con BUILD_TUPLE ) puede producir su Nuevo objeto de clase.