RParadox
RParadox

Reputation: 6871

Assembling Bytecode - PyCode New

The following code produces bytecode output as string. I want to replace some lines of the bytecode and reassemble and exec it. Do I need something like the ByteCodeAssember or can I do this with PyCode New?

http://docs.python.org/2/c-api/code.html#PyCode_New

http://pypi.python.org/pypi/BytecodeAssembler

output

**********      code    **********                                                                                   

type: <type 'str'>                                                                                                   
def test(a,b):                                                                                                       
    return a*b                                                                                                       
test(2,3)                                                                                                            

**********      compiles into the bytecode      **********                                                           

type: <type 'code'>                                                                                                  
  1           0 LOAD_CONST               0 (<code object test at 0x101d1ca30, file "<string>", line 1>)              
              3 MAKE_FUNCTION            0                                                                           
              6 STORE_NAME               0 (test)                                                                    

  3           9 LOAD_NAME                0 (test)                                                                    
             12 LOAD_CONST               1 (2)                                                                       
             15 LOAD_CONST               2 (3)                                                                       
             18 CALL_FUNCTION            2                                                                           
             21 POP_TOP                                                                                              
             22 LOAD_CONST               3 (None)                                                                    
             25 RETURN_VALUE 3  

**********  bytecode    **********

'd\x00\x00\x84\x00\x00Z\x00\x00e\x00\x00d\x01\x00d\x02\x00\x83\x02\x00\x01d\x03\x00S'

code

import dis                                                                                                           
import sys                                                                                                           
import inspect                                                                                                       
import new                                                                                                           

class writer:                                                                                                        
    def __init__(self):                                                                                              
        self.s = ""                                                                                                  

    def write(self,text):                                                                                            
        #print ': ',text                                                                                             
        self.s += text                                                                                               

#save stdout                                                                                                                     
origstdout = sys.stdout                                                                                              
w = writer()                                                                                                         
sys.stdout = w                                                                                                       


s = "def test(a,b):\n\treturn a*b\ntest(2,3)"                                                                        

c = compile(s,'<string>','exec')                                                                                     
# dis calls stdout, so output is in w                                                                                                                         
bytecode = dis.dis(c)                                                                                                

sys.stdout = origstdout                                                                                              

def h(x):                                                                                                            
    print '*'*10 + '\t' + x + '\t' + '*'*10 + '\n'*1                                                                 

h('code')                                                                                                            
print 'type: '+str(type(s))                                                                                          
print s + '\n'                                                                                                       

h('compiles into the bytecode')                                                                                      
print 'type: '+str(type(c))                                                                                          
print w.s

h('bytecode')                                                                                                        
print repr(c.co_code)  

Upvotes: 3

Views: 785

Answers (1)

RParadox
RParadox

Reputation: 6871

Byteplay is a nice wrapper for python code objects. It has its own code class. Code objects is CPython specific and more complicated. To get started certainly better to play with byteplay first.

from byteplay import *                                                                                 

def foo():                                                                                             
    x = 10                                                                                             
    print 'inside ',x                                                                                  
    return 42                                                                                          

c = Code.from_code(foo.func_code)                                                                      
print c.code                                                                                           

ret = foo()                                                                                            
print 'outside: ',ret                                                                                  

c.code[10] = (LOAD_CONST,1000)                                                                         

foo.func_code = c.to_code()                                                                            
print '*'*20                                                                                           
print c.code                                                                                           

ret = foo()                                                                                            

print 'outside: ',ret  

produces

  4           1 LOAD_CONST           10
              2 STORE_FAST           x

  5           4 LOAD_CONST           'inside '
              5 PRINT_ITEM           
              6 LOAD_FAST            x
              7 PRINT_ITEM           
              8 PRINT_NEWLINE        

  6          10 LOAD_CONST           42
             11 RETURN_VALUE         

inside  10
outside:  42
********************

  4           1 LOAD_CONST           10
              2 STORE_FAST           x

  5           4 LOAD_CONST           'inside '
              5 PRINT_ITEM           
              6 LOAD_FAST            x
              7 PRINT_ITEM           
              8 PRINT_NEWLINE        

  6          10 LOAD_CONST           1000
             11 RETURN_VALUE         

inside  10
outside:  1000

Upvotes: 2

Related Questions