Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a class definition always produce the same bytecode?

Say I do:

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

class A(object):
    pass

Now I disassemble it:

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        

Now I add some statements in the class definition:

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

class A(object):
    print 'hello'
    1+1
    pass

And I disassemble again:

  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        

What don't the new statements appear in the new bytecode?

like image 538
usual me Avatar asked Oct 03 '14 15:10

usual me


People also ask

What is Java class file and bytecode?

What is.class File and Bytecode When Java source file is compiled by Java compiler it is converted into Java class file with.class extension. The Java class file contains Java bytecode (highly optimized set of instructions) which is executed by Java Virtual Machine (JVM).

What is bytecode and how does it work?

Bytecode is computer object code that an interpreter converts into binary machine code so it can be read by a computer's hardware processor. The interpreter is typically implemented as a virtual machine (VM) that translates the bytecode for the target platform. The machine code consists of a set of instructions that the processor understands.

Does a Java programmer need to know Java bytecode?

A Java programmer does not need to be aware of or understand Java bytecode at all. However, as suggested in the IBM developerWorks journal, "Understanding bytecode and what bytecode is likely to be generated by a Java compiler helps the Java programmer in the same way that knowledge of assembly helps the C or C++ programmer.".

Can Java bytecode be executed in a virtual machine?

If executing bytecode in a virtual machine is undesirable, a developer can also compile Java source code or bytecode directly to native machine code with tools such as the GNU Compiler for Java (GCJ). Some processors can execute Java bytecode natively. Such processors are termed Java processors .


1 Answers

The new statements are stored in nested bytecode. You can see in your disassembly that another code object is loaded:

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

You need to inspect that code object instead. That's because the class body is executed just like a function object, and the local namespace that call produces is then used to form the class members.

Demo:

>>> 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        

This is the same setup as your first sample; the class body is accessed via the wrapper.__code__.co_consts tuple, which is what the LOAD_CONST byte code refers to; the index is given as 2.

Now we can add a class body:

>>> 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        

Now the class body appears; we can see the byte code that'll be executed when the class body is loaded.

Of note are the LOAD_NAME and STORE_NAME bytecodes executed for each class body; those retrieve the module name and store those as a new local name __module__, so that your class will end up with a __module__ attribute once created.

The LOAD_LOCALS bytecode then gathers all the local names produced in this 'function' and returns that to the caller, so that the BUILD_CLASS bytecode can use that together with the 'A' string and the object bases tuple (created with BUILD_TUPLE) can produce your new class object.

like image 183
Martijn Pieters Avatar answered Oct 21 '22 00:10

Martijn Pieters