Auto-Generative Expression Trees for Fun and Profit
Verfasst: Dienstag 12. August 2014, 17:10
Jetzt neu mit Monaden! 
Übers Wochenende hab ich das hier gebaut: http://www.python-forum.de/pastebin.php?mode=view&s=397
Es benötigt codegen, welches es hier gibt: https://pypi.python.org/pypi/codegen/1.0
Sowas kann man damit machen:Ergebnis:Natürlich könnte man in dem Beispiel oben auch einfach einen String an foo() und bar() übergeben. Den syntaktisch korrekt dynamisch zu erzeugen dürfte allerdings nicht so einfach sein. Außerdem hat man, wenn man einen AST hat, auch die Möglichkeit, diesen zu transformieren. In der Doku zum ast Modul gibt es AFAIR ein Beispiel, wie man Namens-Lookup in einen dict-Lookup transformieren kann.
Deswegen könnte man sich zB. nicht nur vorstellen, dass foo() und bar() in einem anderen Prozess (und auf einem anderen Rechner) leben, sondern dass man sich einen Interpreter für Expression-Objekte baut, die direkt auf dem AST operieren. Man könnte dann etwa sowas wie LINQ damit bauen, oder, was mein Einsatzzweck dafür sein wird, eine EDSL für Logikprogrammierung.
Es ist weder fertig, noch gibt es irgendwelche Dokumentation. Wenn man Closures und Dekoratoren versteht (und evtl. Monaden), und die Art und Weise, wie der Attribut-Lookup in Python funktioniert, dann sollte der Code gut zu verstehen sein. Falls nicht, bitte Laut geben, ich erkläre es gerne.
Es funktioniert übrigens erst ab Python 3.2.

Übers Wochenende hab ich das hier gebaut: http://www.python-forum.de/pastebin.php?mode=view&s=397
Es benötigt codegen, welches es hier gibt: https://pypi.python.org/pypi/codegen/1.0
Sowas kann man damit machen:
Code: Alles auswählen
def test(a, b):
return a * b
def foo(formula):
x, y, z = 3, 4, 11
return expr_eval(formula, globals(), locals())
def bar(formula):
x, y, z = 'hey', 'ho', 4
return expr_eval(formula, globals(), locals())
def main():
x = Name('x')
y = Name('y')
z = Name('z')
test = Name('test')
exprs = (
x + test(y, z),
test(x, z) + y,
)
for expr in exprs:
print('------------------------------')
print(expr)
print()
print('foo:', foo(expr))
print('bar:', bar(expr))
print()
print(repr(expr))
print()
if __name__ == '__main__':
main()
Code: Alles auswählen
------------------------------
x + test(y, z)
foo: 47
bar: heyhohohoho
BinOp(left=Name(id='x', ctx=Load()), op=Add(), right=Call(func=Name(id='test', ctx=Load()), args=[Name(id='y', ctx=Load()), Name(id='z', ctx=Load())], keywords=[], starargs=None, kwargs=None))
------------------------------
test(x, z) + y
foo: 37
bar: heyheyheyheyho
BinOp(left=Call(func=Name(id='test', ctx=Load()), args=[Name(id='x', ctx=Load()), Name(id='z', ctx=Load())], keywords=[], starargs=None, kwargs=None), op=Add(), right=Name(id='y', ctx=Load()))
Deswegen könnte man sich zB. nicht nur vorstellen, dass foo() und bar() in einem anderen Prozess (und auf einem anderen Rechner) leben, sondern dass man sich einen Interpreter für Expression-Objekte baut, die direkt auf dem AST operieren. Man könnte dann etwa sowas wie LINQ damit bauen, oder, was mein Einsatzzweck dafür sein wird, eine EDSL für Logikprogrammierung.
Es ist weder fertig, noch gibt es irgendwelche Dokumentation. Wenn man Closures und Dekoratoren versteht (und evtl. Monaden), und die Art und Weise, wie der Attribut-Lookup in Python funktioniert, dann sollte der Code gut zu verstehen sein. Falls nicht, bitte Laut geben, ich erkläre es gerne.
Es funktioniert übrigens erst ab Python 3.2.