Seite 1 von 1

Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 14:11
von ravenheart
Ich lese eine csv-Tabelle aus und möchte nun eine Funktion

Code: Alles auswählen

select_rows
Ähnlich wie SQL

Funktionsaufrufe sollten wenn möglich

Code: Alles auswählen

select_rows("time > 10 and speed < 200")
sein. Wobei das bedeutet, dass der Wert der Spalte time größer 10 sein soll und gleichzeitig speed < 200.

Leider weiß ich nicht wie man das am besten implementier, vor allem, da aus der csv nur strings gelesen werden und ich manchmal Zahlen brauche

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 14:17
von EyDu
Hallo.

Warum verarbeitest du deine Daten nicht einfach mit SQLite?

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 14:31
von ravenheart
Wüsste ich auch gerne...

Es soll sowohl eine Datenbankversion geben, als auch eine reine csv-Version.
Wenn es nach mir ginge würden sowieso alle Messwerte gleich in einer Datenbank angelegt, aber es geht nicht nach mir.

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 14:35
von EyDu
Du kannst durchaus die Schnittstelle zu csv-Dateien beibehalten. SQLite bietet auch die Möglichkeit, eine Datenbank im Speicher anzulegen, ohne den Umweg über eine Datei zu gehen. Du musst dann nur noch deine Tabellen in SQL übersetzen. Schau dazu am besten in die Dokumentation des SQLite-Moduls und Suche nach ":memory:".

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 14:42
von ravenheart
Ich kenne das :memory:,

aber mir wurde klar gesagt, dass das hier nicht gewünscht ist, es gibt bisher ein skript dafür, welches ich ersetzen soll.

Code: Alles auswählen

select_rows -c  xxx  -o  [eq | lt |gt |neq | leq | get ] -v yyy   [-d] 
ist der bisherige Aufbau

Wobei

Code: Alles auswählen

-c   Spaltenname
-o Operation (lt = less than  ...
-v value Wert zum Vergleichen
-d -optional : sorgt dafür dass Stringvergleich statt float genommen wird
Ich könnte das ganze jetzt 1:1 nachbauen, bin aber der Meinung dass das schöner ginge und suche nun nach Möglichkeiten.

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 14:51
von EyDu
Ok, wenn du Benutzereingaben verarbeiten musst, dann kommst du natürlich um das Parsen nicht herum. Dann hilft dir das ast-Modul weiter. Den gewonnen Syntax-Baum musst du nur noch prüfen, ob dieser lediglich die erlaubten Elemente enthält und anschließend kannst du ihn auswerten.

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 15:15
von ravenheart
ich dachte zunächst an etwas einfacheres

Code: Alles auswählen

def sel_row(lrenaming = None , exprssion = None):
    varnames_str = expression.split(:)[1]
    varnames = [e.strip() for e in varnames_str.split(",")]

    lambda_func = eval("lambda " + expression)

    for line in file:
       # get values...
       values = ... 
       # evaluate lambda function with values
       result = lambda_func(*values)

Hat halt noch einige nachteile, jedoch einen kompletten syntaxbaum aufzusetzen? Das ist verdammt viel Arbeit

Edit:
Aber da ich ohnehin nur Ausdrücke wie

x < 3 or y>2

haben möchte, bin ich relativ sicher, dass es da schon was fertiges gibt

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 15:33
von EyDu
Hast du dir das ast-Modul überhaupt angeschaut? Dort wird der gesamte Baum für dich erzeugt und eine Auswertung ist geradezu lächerlich einfach. Deine Anforderungen übertriffst du damit sicher um Längen und die Implementierung sollte locker in einer Stunde erledigt sein.

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 17:14
von ms4py
Habe was vergleichbares gemacht um mit `ast` Funktionen mit Parameter und laufender Variable wie z.B. 2*x + p['a'] zu erkennen.
* Erklärung: https://bitbucket.org/ms4py/sitforc/dow ... parser.pdf
* Code: https://bitbucket.org/ms4py/sitforc/src ... cparser.py

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 21:18
von ravenheart
Ich bin leider hoffnungslos überfordert.

Ich weiß nicht mal , ob mein Ansatz richtig ist.

Bisher versuche ich, die Benutzereingabe mit Hilfe von compile in ein ast-Objekt zu bringen

Code: Alles auswählen

src = "time > 10 and mode = 'unset'"
ast_obj = compile(src, "<string>", "exec", ast.PyCF_ONLY_AST)
Ich erhalte sogar ein Ast-Objekt

Code: Alles auswählen

for a in ast.walk(ast_obj):
  print a
Liefert mir sogar halbwegs brauchbare Sachen, aber so richtig weiter weiß ich noch nicht.

Könnt ihr mir helfen? (Wie gesagt, ich hab KEINE ahnung, ob dasd was ich bisher getan hab auch nur halbwegs Sinn macht)

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 21:26
von ms4py
Konntest mit dem 4 seitigen PDF etwa nichts anfangen? Dein Code sieht nicht so aus, als ob du das berücksichtigt hast...

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 22:01
von ravenheart
Ich muss sagen, das was du da geschrieben hast, ist schon "fortgeschrittener". Ich lerne grad mal Python seit nem Monat und da ist das doch recht hart.
Im Moment versuche ich, noch ein wenig mit ast herumzuspielen, um den Aufbau etwas genauer zu verstehen.

Ich werde etwas länger brauchen um das zu verstehen.
Es fängt mit

Code: Alles auswählen

ast.parse(..., mode="eval")
an (Ist es Zufall dass deine Funktionen alle eval heißen <es gibt eine Erklärung für eval im pdf, aber ob das hier schon zutrifft?

Die Methode install ist für mich ein wahres Rätsel.

Ich werde länger brauchen, um das zu verstehen. Deswegen noch die Spielereien.

Ich danke dennoch für die beiden Dokument, ich hoffe sie werden mir noch helfen

EDIT:
Sowet ich einsehen kann, fügst du den Typen von ast wie ast.Expression neue Methoden zu, welche du dann aufrufst. Aber wie gesagt, ich brauche Zeit.
Jetz seh ich mir mal den Unterschied ast.Expression und Module an

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 22:09
von EyDu
Hallo.

Der ast.NodeVisitor nimmt dir die ganze Arbeit des Traversierens ab. Und wenn du mal die Attribute nicht kennst, dann hilft dir die "dir"-Funktion. Außerdem solltest du "ast.parse" verwenden statt "compile", dann sparst du dir auch die ganzen Parameter.

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Dienstag 30. November 2010, 22:27
von ms4py
Ja, ich füge allen ast-Klassen die Methode `eval` hinzu, und kann die dann Bottom-Up aufrufen.

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Mittwoch 1. Dezember 2010, 13:42
von ravenheart
Es wird langsam aber sicher peinlich...
Ich war grad in der Bibliothek und habe sämtlichste Pythonbücher durchforstet und nirgends etwas über ast gelesen ...

Also um mal eine Orientierung zu geben:

Ich versuche aus

Code: Alles auswählen

 "impl > 3 and mode == 'unset'"

Code: Alles auswählen

 " 3 > 3  and mode == 'unset'"
zu kreieren und dann auszuführen.

Mein Ansatz bisher:

Code: Alles auswählen

''' Diese Klasse ist nur zum Betrachten möglicher Zwischenschritte'''
class v(ast.NodeVisitor):
  def generic_visit(self,node):
    print type(node).__name__
    ast.NodeVisitor.generic_visit(self, node)
  def visit_Name(self, node):
    print "Name: ", node.id

''' Eigentliche Bearbeitung'''
class t(ast.NodeTransformer):
  ''' Wenn impl gefunden wurde, mache daraus einen Num-Knoten mit dem Wert 3 '''
  def visit_Name(self,node):
    if node.id =="impl":
      return ast.Num(3)
    else:
      return node
Ausführung:

Code: Alles auswählen

my = ast.parse("impl > 3 and mode =='unset'", mode="eval")
t().visit(my)
v().visit(my)

--->
Expression
BoolOp
And
Compare
Num
Gt
Num
Compare
Name:  mode
Eq
Str
Das sieht eigentlich ganz gut aus, dachte ich bisher.
Aber nun;

Code: Alles auswählen

c = compile(my, "<string>", mode="eval")

--->
required field "lineno" missing from expr
Ich kann die Fehlermeldung nicht deuten und bitte nochmals um Hilfe und Korrektur

Wahrscheinlich muss ich noch copy_location aufrufen


EDIT:

Code: Alles auswählen

class t(ast.NodeTransformer):
   ....:     def visit_Name(self,node):
   ....:         if type(d[node.id]).__name__ in ["int", "float"]:
   ....:             new_node = ast.Num(d[node.id])
   ....:             ast.copy_location(new_node, node)
   ....:             return new_node
   ....:         else:
   ....:             new_node = ast.Str(d[node.id])
   ....:             ast.copy_location(new_node, node)
   ....:             return new_node
   ....: 
scheint zu funktionieren, wobei d ein dictionary ist.
Aber wenn ich die Dokumentation richtig verstehe, sollte das, was ich vorhabe mir Subscript etwas leichter gehen.
Verbesserungen erwünscht

Re: Lambdafunktionen Eval oder Parsen?

Verfasst: Mittwoch 1. Dezember 2010, 13:50
von EyDu
Hallo.

Versuche doch mal "my.eval", so wie es auch in dem Beispiel von ms4py steht.

Du solltest dir angewöhnen, Klassen richtig zu bennen und vernünftig (mit vier Leerzeichen) einzurücken. Das ist besonders dann sinnvoll, wenn dir andere helfen sollen. Außerdem sind Strings keine Kommentare, benutze also letztere wenn du etwas erläuterst.