2009-09-26 12 views
10

Voglio intrufolarmi con l'interprete Python e provare a creare una piccola DSL. Esiste un modulo in cui posso fare qualcosa come questo codice teorico (simile agli alberi di espressione LINQ)?C'è un modo per generare codice bytecode Python?

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

O sarebbe semplicemente più semplice generare codice sorgente Python? Questo potrebbe essere reso più semplice usando C o SWIG o Cython?

+0

Data la potenza espressiva enorme di linguaggi OO (Python in particolare) un DSL è abbastanza stupido. Basta scrivere il Python. Se fornisci buone definizioni di classe, hai un Python "simile a DSL" e non ne hai bisogno. –

risposta

10

Lavorare tramite ast e compilare l'albero in bytecode, come suggerisce un'altra risposta, è probabilmente il più semplice; generare fonti e compilarle, quasi altrettanto bene.

Tuttavia, per esplorare approcci di livello inferiore, controllare i collegamenti da this page; Ho trovato particolarmente utile byteplay (attualmente non funziona su 2.6 o 3. *, solo 2.4 o 2.5, ma penso che risolverlo per 2.6 dovrebbe essere facile, come già discusso nel suo tracker). Non ho usato lo stesso tipo di Phil Eby BytecodeAssembler, ma vista la reputazione dell'autore sono sicuro che vale la pena di provarlo!

+0

+1 Nice links :) –

+0

Ottima risposta come sempre. :-) –

0

Estrai il modulo disassembler trovato qui:

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

+0

L'unica cosa è che volevo assemblare il bytecode, non * dis * assemblarlo. :-) –

+0

ahh buon punto, scusate per il fatto che;) tuttavia la cosa bella del modulo disassemblatore è che consente di guardare il bytecode che viene generato oltre a dare le specifiche alle istruzioni del bytecode. – Nope

5

In Python 2.x, è in genere sarebbe avvicinarsi a questo con il compiler module e il suo sub-modulo ast (a meno di notare questo modulo è deprecato dalla versione 2.6). In Python 3.X, dovresti usare solo ast.

Entrambi offrono una funzione compile() che passerà dalla sorgente/AST a "un oggetto codice che può essere eseguito dall'istruzione exec o eval()".

1

Fernando Meyer recently wrote a blog post che spiega come utilizzare la direttiva # coding per specificare le proprie estensioni su Python. Esempio (la definizione del formato reale è in pyspec.py e 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

E 'più facile per generare il codice Python ed eseguirlo. Se lo fai puoi anche eseguirne il debug più facilmente poiché c'è una vera fonte per la visualizzazione del debugger. Vedi anche l'articolo di Malte Borchs sul numero di luglio della rivista Python, di cui parla tra l'altro.

1

Aggiornamento per Python3 - c'è anche un assemblatore molto interessante zachariahreed/byteasm.

Attualmente l'unico che funziona per me in Py3. Ha molto bello & API pulita:

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