2009-09-26 17 views
10

Quiero hackear con el intérprete de Python y tratar de crear una pequeña DSL. ¿Hay algún módulo donde pueda hacer algo como este código teórico (similar a los árboles de expresión LINQ)?¿Hay alguna forma de generar programáticamente bytecode de Python?

expression_tree = Function(
    Print(
     String('Hello world!') 
    ) 
) 
compile_to_bytecode(expression_tree) 

¿O simplemente sería más fácil generar el código fuente de Python? ¿Podría esto ser más fácil usando C o SWIG o Cython?

+0

Dada la tremenda fuerza expresiva de los lenguajes orientados a objetos (Python en particular) una conexión DSL es bastante tonto. Solo escribe el Python. Si se proporciona buenas definiciones de clase, tiene un Python "DSL-like" y no lo necesita. –

Respuesta

10

Trabajar a través de ast y compilar el árbol en bytecode, como sugiere otra respuesta, es probablemente el más simple; generando fuentes y compilando esas, casi tan buenas.

Sin embargo, para explorar los enfoques de nivel inferior, consulte los enlaces de this page; He encontrado byteplay especialmente útil (actualmente no funciona en 2.6 ni 3. *, solo 2.4 o 2.5, pero creo que corregirlo para 2.6 debería ser fácil, como se discute actualmente en su rastreador). No he usado el BytecodeAssembler de características similares de Phil Eby, pero dada la reputación del autor, estoy seguro de que vale la pena echarle un vistazo.

+0

+1 Enlaces agradables :) –

+0

Gran respuesta como siempre. :-) –

0

Salida del módulo desensamblador encontrar aquí:

http://docs.python.org/library/dis.html

+0

Lo único es que quería ensamblar bytecode, no * dis * assemble. :-) –

+0

ahh buen punto, disculpa de eso;) Sin embargo, lo bueno del módulo desensamblador es que te permite ver el bytecode que se genera y dar detalles sobre las instrucciones del bytecode. – Nope

5

En Python 2.x, lo más habitual es abordar esto con el compiler module y su ast submódulo (pero tenga en cuenta este módulo está en desuso desde la versión 2.6). En Python 3.X, usaría solo ast.

Ambos ofrecen una función compile() que irá de source/AST a "un objeto de código que se puede ejecutar con la instrucción exec o eval()".

1

Fernando Meyer recently wrote a blog post explicando cómo usar la directiva # coding para especificar sus propias extensiones a Python. Ejemplo (la definición de formato real es en pyspec.py y tokenizer.py):

# coding: pyspec 

class Bow: 
    def shot(self): 
     print "got shot" 

    def score(self): 
     return 5 

describe Bowling: 
    it "should score 0 for gutter game": 
     bowling = Bow() 
     bowling.shot() 
     assert that bowling.score.should_be(5) 
2

Es más fácil generar el código Python y ejecutarlo. Si lo hace, también puede depurarlo más fácilmente ya que existe una fuente real para que se muestre el depurador. Véase también el artículo de Malte Borchs en la edición de julio de la revista Python, donde habla sobre esto, entre otras cosas.

1

Actualizando para Python3 - también hay un ensamblador muy interesante zachariahreed/byteasm.

En realidad, el único que trabaja para mí en Py3. Tiene muy buen & API limpia:

>>> import byteasm, dis 
>>> b = byteasm.FunctionBuilder() 
>>> b.add_positional_arg('x') 
>>> b.emit_load_const('Hello!') 
>>> b.emit_load_fast('x') 
>>> b.emit_build_tuple(2) 
>>> b.emit_return_value() 
>>> f = b.make('f') 
>>> f 
<function f at 0xb7012a4c> 
>>> dis.dis(f) 
    1   0 LOAD_CONST    0 ('Hello!') 
       3 LOAD_FAST    0 (x) 
       6 BUILD_TUPLE    2 
       9 RETURN_VALUE 
>>> f(108) 
('Hello!', 108) 
Cuestiones relacionadas