2009-09-26 20 views
10

Ich möchte mit dem Python-Interpreter herumhacken und versuchen, eine kleine DSL zu erstellen. Gibt es ein Modul, in dem ich so etwas wie diesen theoretischen Code machen kann (ähnlich wie LINQ-Expression-Bäume)?Gibt es eine Möglichkeit programmgesteuert Python-Bytecode zu generieren?

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

Oder wäre es nur einfacher, nur Python-Quellcode zu generieren? Könnte dies mit C oder SWIG oder Cython einfacher gemacht werden?

+0

Angesichts der enormen Ausdruckskraft der OO-Sprachen (insbesondere Python) ist ein DSL ziemlich albern. Schreib einfach das Python. Wenn Sie sich gute Klassendefinitionen geben, haben Sie ein "DSL-ähnliches" Python und brauchen das nicht. –

Antwort

10

Arbeiten über ast und das Kompilieren der Baum in Bytecode, wie eine andere Antwort vorschlägt, ist wahrscheinlich am einfachsten; Quellen erzeugen und kompilieren, fast so gut.

Um jedoch Ansätze auf niedrigerer Ebene zu erkunden, überprüfen Sie die Links von this page; Ich habe byteplay besonders nützlich gefunden (derzeit funktioniert nicht auf 2.6 noch 3. *, nur 2.4 oder 2.5, aber ich denke, es für 2.6 beheben sollte einfach sein, wie derzeit in seinem Tracker diskutiert). Ich habe Phil Ebys ähnlich ausgestattete BytecodeAssembler nicht verwendet, aber angesichts des Rufs des Autors bin ich mir sicher, dass es sich lohnt, es auszuprobieren!

+0

+1 Schöne Links :) –

+0

Große Antwort wie immer. :-) –

0

Schauen Sie sich den Disassembler-Modul hier:

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

+0

Das einzige Ding ist, dass ich Bytecode zusammenbauen wollte, nicht * dis * es zusammenbauen. :-) –

+0

Ahh guter Punkt, tut mir leid, dass;) aber das Schöne an dem Disassembler-Modul ist, können Sie den Bytecode, der generiert wird, sowie die Besonderheiten der Bytecode-Anweisungen. – Nope

5

In Python 2.x, würden Sie in der Regel diesen Ansatz mit dem compiler module und seine ast-Submodul (aber beachten Sie dieses Modul ab Version ist veraltet 2.6). In Python 3.X würden Sie nur ast verwenden.

Beide bieten eine compile()-Funktion, die von Quelle/AST auf "ein Code-Objekt, das durch die exec-Anweisung oder eval() ausgeführt werden kann."

1

Fernando Meyer recently wrote a blog post erläutert, wie Sie die # coding-Direktive verwenden, um Ihre eigenen Erweiterungen für Python anzugeben. Beispiel (die tatsächliche Format Definition ist in pyspec.py und 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 ist einfacher, Python-Code zu generieren und ausführen. Wenn Sie das tun, können Sie es auch leichter debuggen, da es tatsächlich eine Quelle für den Debugger gibt. Siehe auch Malte Borchs Artikel in der Juli-Ausgabe des Python Magazins, wo er unter anderem darüber spricht.

1

Aktualisierung für Python3 - es gibt auch sehr interessante Assembler zachariahreed/byteasm.

Eigentlich der einzige, der für mich in Py3 arbeitet. Es hat sehr schön & clean API:

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