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?
The new statements are stored in nested bytecode. You can see in your disassembly that another code object is loaded:
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:
This is the same setup as your first sample; the class body is accessed via the
wrapper.__code__.co_consts
tuple, which is what theLOAD_CONST
byte code refers to; the index is given as2
.Now we can add a class body:
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
andSTORE_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 theBUILD_CLASS
bytecode can use that together with the'A'
string and theobject
bases tuple (created withBUILD_TUPLE
) can produce your new class object.