Baeume in Python

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Hi BlackJack,
BlackJack hat geschrieben:Okay ich bin jetzt bei folgendem gelandet:
Hier noch eine kleine Funktion, die aus einem Parser-Ergebnis wieder Quelltext erzeugt:

Code: Alles auswählen

def ast2str(ast):
    def template2str(template):
        name, body = template
        return ('template %s := ' % name) + node2str(body)
    
    def node2str(node):
        if isinstance(node, basestring):
            return node
        node_type = node.getName()
        if node_type == 'assignments':
            result = ', '.join('%s := %s' % (identifier, node2str(value))
                               for identifier, value in node)
        elif node_type == 'list':
            result = ', '.join(map(node2str, node))
        else:
            raise Exception('Unknown block type %r' % node_type)
        return '{ %s }' % result
    
    return '\n'.join(map(template2str, ast))
vielen Dank nochmals fuer deine Hilfsbereitschaft :D . Dein Code funktioniert super. Ich habe nur mit der 2ten Funktion Schwierigkeiten (Python Version 2.3.3). Der Interpreter meckert dort:
for identifier, value in node)
_^
SyntaxError: invalid syntax
Er mag die Schleife an dieser Stelle anscheinend nicht. Falls ich die betreffende Zeile aendere in

Code: Alles auswählen

for identifier, value in node:
    result = ', '.join('%s := %s' % (identifier, node2str(value)) )
was meinem Verstaendnis nach die Funktion an sich nicht veraendert, dann laeufts durch allerdings mit folgendem Ergebnis:

Code: Alles auswählen

 template Typ2 := { a, 1, 1,  , :, =,  , {,  , {,  , {,  , a, ,,  , 1, ,,  , 3, ,,  ,  , ,,  , :, ,,  , =, ,,  ,  , ,,  , {, ,,  ,  , ,,  , a, ,,  , ,, ,,  ,  , ,,  , 1, ,,  , ,, ,,  ,  , ,,  , 4, ,,  , ,, ,,  ,  , ,,  ,  , ,,  , ,, ,,  ,  , ,,  , :, ,,  , ,, ,,  ,  , ,,  , =, ,,  , ,, ,,  ,  , ,,  ,  , ,,  , ,, ,,  ,  , ,,  , 1, ,,  , ,, ,,  ,  , ,,  , 7, ,,  ,  , ,,  , },  , },  , },  , } }
Ich mach mich erst mal an die Erweiterung mit der Parameterliste.
Wie lange programmierst du eigentlich schon in Python?
Im Moment finde ich den Einstieg in Python doch etwas muehselig, da ich es von C her gewohnt bin, mir die meisten Funktionen selbst zu programmieren. In Python hingegen geht dies auch, jedoch wenn man die Standardklassen und deren Funktionen kennt, scheint man diese nur noch kombinieren zu muessen und man loest das gleiche Problem mit einem Bruchteil an Quellcodezeilen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

der_Gerhard hat geschrieben:Im Moment finde ich den Einstieg in Python doch etwas muehselig, da ich es von C her gewohnt bin, mir die meisten Funktionen selbst zu programmieren. In Python hingegen geht dies auch, jedoch wenn man die Standardklassen und deren Funktionen kennt, scheint man diese nur noch kombinieren zu muessen und man loest das gleiche Problem mit einem Bruchteil an Quellcodezeilen.
Und was daran ist mühselig?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

der_Gerhard hat geschrieben: vielen Dank nochmals fuer deine Hilfsbereitschaft :D . Dein Code funktioniert super. Ich habe nur mit der 2ten Funktion Schwierigkeiten (Python Version 2.3.3). Der Interpreter meckert dort:
for identifier, value in node)
_^
SyntaxError: invalid syntax
Er mag die Schleife an dieser Stelle anscheinend nicht. Falls ich die betreffende Zeile aendere in

Code: Alles auswählen

for identifier, value in node:
    result = ', '.join('%s := %s' % (identifier, node2str(value)) )
was meinem Verstaendnis nach die Funktion an sich nicht veraendert,
Doch das verändert die Funktion: Du weist `result` in jedem Schleifendurchlauf einen anderen, einzelnen Wert zu. Mach aus dem Generator Ausdruck in meinem Quelltext am besten eine `List Comprehension`, also innerhalb der runden Klammern des `join()` nochmal eckige um den Ausdruck:

Code: Alles auswählen

result = ', '.join(['%s := %s' % (identifier, node2str(value))
                     for identifier, value in node])
Wie lange programmierst du eigentlich schon in Python?
Ich bin 2003 auf Python gestossen als ich in Perl ein Problem lösen wollte, das verschachtelte Datenstrukturen zur Lösung benötigte.

Programmieren habe ich vor "Urzeiten" auf'm C64 angefangen. Damals noch BASIC und Assembler.
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Hi Leonidas,
Leonidas hat geschrieben:
der_Gerhard hat geschrieben:Im Moment finde ich den Einstieg in Python doch etwas muehselig, da ich es von C her gewohnt bin, mir die meisten Funktionen selbst zu programmieren. In Python hingegen geht dies auch, jedoch wenn man die Standardklassen und deren Funktionen kennt, scheint man diese nur noch kombinieren zu muessen und man loest das gleiche Problem mit einem Bruchteil an Quellcodezeilen.
Und was daran ist mühselig?
wenn ich mich dran mache und eine Funktion komplett selbst zu schreiben und mir anschliessend jemand eine Loesung praesentiert, die das gleiche mit 1/10 der Quellcodezeilen realisiert, dann ist das doch schon ziemlich deprimierend. Wenn man erst mal einen Ueberblick der Standardfunktionen hat, stelle ich es mir schon etwas einfacher vor.
Ich finde es im Moment muehselig, mir die ganzen Standardfunktionen anzueignen, was natuerlich zum Ergebnis fuehrt, dass man spaeter um so weniger Arbeit hat. Ich finde Python auf jeden Fall von Tag zu Tag besser.

Gruss
Gerhard
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

der_Gerhard hat geschrieben:wenn ich mich dran mache und eine Funktion komplett selbst zu schreiben und mir anschliessend jemand eine Loesung praesentiert, die das gleiche mit 1/10 der Quellcodezeilen realisiert, dann ist das doch schon ziemlich deprimierend.
Das passiert vielen Leuten. Auch mir passiert es manchmal, dass jemand das gleiche Problem wie ich sowohl kürzer als auch eleganter und leserlicher löst. Das ist aber Sache der Erfahrung (sowohl Erfahrung mit Python als auch Programmieren im allgemeinen).
der_Gerhard hat geschrieben:Wenn man erst mal einen Ueberblick der Standardfunktionen hat, stelle ich es mir schon etwas einfacher vor.
Du solltest dir vielleicht die, meiner Meinung nach exzellente, Python Quick Reference ansehen.
der_Gerhard hat geschrieben:Ich finde es im Moment muehselig, mir die ganzen Standardfunktionen anzueignen, was natuerlich zum Ergebnis fuehrt, dass man spaeter um so weniger Arbeit hat.
Ich finde es nicht so sehr sinnvoll auswendig zu lernen, welche Funktion was macht. Ich nutze lieber learning by doing: ein Beispiel: ich habe mal eine for-Schleife gebraucht, die sowohl durch eine Liste geht, als auch die Position der Liste. Deswegen habe ich im Forum hier gefragt und Dookie hat mir eine Lösung mit zip() gepostet. Monate später habe ich ein Snippet von BlackJack gesehen, welches genau das gleiche macht, jedoch mit enumerate(). Seitdem weiß ich, wenn ich sowas brauche: aha, es gibt die Funktion enumerate() zu dem Zweck.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Hi Black Jack,
BlackJack hat geschrieben:Okay ich bin jetzt bei folgendem gelandet:
[snip]
Hier noch eine kleine Funktion, die aus einem Parser-Ergebnis wieder Quelltext erzeugt:

Code: Alles auswählen

def ast2str(ast):
    def template2str(template):
        name, body = template
        return ('template %s := ' % name) + node2str(body)
[snip]
langsam wird es mir ein wenig peinlich, deine Hilfe wieder anzufordern, aber ich komme wiedermal nicht weiter:
Die template_signatur habe ich erweitert, was auch gut funktioniert hat.

Code: Alles auswählen

parameter_list = identifier + '(' + delimitedList(Keyword('template') + 
                                          identifier + identifier) + ')'
template_signature = (identifier + 
                                         parameter_list).setResultsName('template_signature')
Da "name" jetzt aus mehreren Woertern besteht funktioniert die erste Zuweisung

Code: Alles auswählen

name, body = template
in der Funktion ast2str(ast) nicht mehr.
Ein Ansatz war bisher, das Ergebnis als Liste umzuwandeln und anschliessend ueber die einzelnen Signaturelemente zu laufen, etwa so:

Code: Alles auswählen

a = template.asList()
for i in range(0,len(erg[0]-2)):
b= a[0][i]
c= c.join(b)
Dieser Versuch war leider nicht sehr erfolgreich. Siehst du dort eine simple Loesung?
Zu was anderem: Da einzelne Templates spaeter miteinander verglichen werden muessen, ist es fur die Laufzeit von Vorteil, die Templates nach den Keys in jeder Ebene zu sortieren. Die Sortierfunktion fuer Listen ist da nicht geeignet, da sie mir auch die Schluessel-Wert Paare umsortiert, so dass spaeter nicht mehr erkennbar ist was jetzt Wert und was Schluessel ist. Gibt es dafuer andere sinnvolle Standardfunktionen?

Gruss
Gerhard
BlackJack

der_Gerhard hat geschrieben: langsam wird es mir ein wenig peinlich, deine Hilfe wieder anzufordern, aber ich komme wiedermal nicht weiter:
Die template_signatur habe ich erweitert, was auch gut funktioniert hat.

Code: Alles auswählen

parameter_list = identifier + '(' + delimitedList(Keyword('template') + 
                                          identifier + identifier) + ')'
template_signature = (identifier + 
                                         parameter_list).setResultsName('template_signature')
Da "name" jetzt aus mehreren Woertern besteht funktioniert die erste Zuweisung

Code: Alles auswählen

name, body = template
in der Funktion ast2str(ast) nicht mehr.
Erstmal eine Frage zur Grammatik der Signatur: Da folgen ja zwei Bezeichner aufeinander vor der Parameterliste: Das eine ist eine Typbezeichnung und das andere der Name des Templates? Warum ist einer dieser beiden Bezeichner denn Bestandteil der Parameterliste und der andere nicht?

Ansonsten: Wenn Du verschachtelte "Listen" als Ergebnis haben möchtest, dann macht man das mit `Group`. Wenn Du also ein `Group()` um die Signatur setzt, dann ist die gesamte Signatur im Ergebnis eine (Unter)Liste. Innerhalb der Signatur bietet es sich dann an, das mit der Parameterliste auch wieder zu tun um dann später in einer Schleife darüber laufen zu können.

Dann müsste es in der Funktion nicht mehr ``name, body = template`` heissen, sondern ``signature, body = template`` und danach dann eben entsprechender Quelltext, der die Signatur "auseinandernimmt". Also zum Beispiel die ersten beiden Elemente sind Typ und Templatename und dann folgt eine Liste mit Parametern. Die vielleicht wieder Listen mit zwei Elementen (Typ und Name) sind.
Ein Ansatz war bisher, das Ergebnis als Liste umzuwandeln und anschliessend ueber die einzelnen Signaturelemente zu laufen, etwa so:

Code: Alles auswählen

a = template.asList()
for i in range(0,len(erg[0]-2)):
b= a[0][i]
c= c.join(b)
Dieser Versuch war leider nicht sehr erfolgreich. Siehst du dort eine simple Loesung?
Wie gesagt, wenn man die Elemente in der Grammatik entsprechend gruppiert und verschachtelte Listen erstellt, dann sollte das lesbarer gehen. Das mit den Indices da oben versteht nach einem halben Jahr kein Mensch mehr auf Anhieb.
Zu was anderem: Da einzelne Templates spaeter miteinander verglichen werden muessen, ist es fur die Laufzeit von Vorteil, die Templates nach den Keys in jeder Ebene zu sortieren. Die Sortierfunktion fuer Listen ist da nicht geeignet, da sie mir auch die Schluessel-Wert Paare umsortiert, so dass spaeter nicht mehr erkennbar ist was jetzt Wert und was Schluessel ist. Gibt es dafuer andere sinnvolle Standardfunktionen?
Ich hab jetzt keine genaue Vorstellung was da genau gemacht werden soll. Ich würde das Ergebnis vom Parsen vom Gefühl her aber auch eher als Zwischenergebnis ansehen und daraus dann eine Objekt aus verschiedenen Objekten/Klassen zusammenbauen, die dann die entsprechenden Funktionalitäten hätten, die ich bräuchte um damit zu arbeiten. Also zumindest wenn die Aufgabe nicht ganz trivial wäre und auf diesem "Abstract Syntax Tree" supereinfach zu erledigen wäre.
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

BlackJack hat geschrieben:
der_Gerhard hat geschrieben:

Code: Alles auswählen

parameter_list = identifier + '(' + delimitedList(Keyword('template') + 
                                          identifier + identifier) + ')'
template_signature = (identifier + 
                                         parameter_list).setResultsName('template_signature')
Erstmal eine Frage zur Grammatik der Signatur: Da folgen ja zwei Bezeichner aufeinander vor der Parameterliste: Das eine ist eine Typbezeichnung und das andere der Name des Templates? Warum ist einer dieser beiden Bezeichner denn Bestandteil der Parameterliste und der andere nicht?
Okay, das habe ich nicht richtig abgebildet. Den ersten identifier sollte man natuerlich mit zur Signatur nehmen. Also so:

parameter_list = '(' + delimitedList(Keyword('template') +
identifier + identifier) + ')'
template_signature = (identifier + identifier +
parameter_list).setResultsName('template_signature')

[snip: Gute Tipps]
BlackJack hat geschrieben:
der_Gerhard hat geschrieben:Zu was anderem: Da einzelne Templates spaeter miteinander verglichen werden muessen, ist es fur die Laufzeit von Vorteil, die Templates nach den Keys in jeder Ebene zu sortieren. Die Sortierfunktion fuer Listen ist da nicht geeignet, da sie mir auch die Schluessel-Wert Paare umsortiert, so dass spaeter nicht mehr erkennbar ist was jetzt Wert und was Schluessel ist. Gibt es dafuer andere sinnvolle Standardfunktionen?
Ich hab jetzt keine genaue Vorstellung was da genau gemacht werden soll. Ich würde das Ergebnis vom Parsen vom Gefühl her aber auch eher als Zwischenergebnis ansehen und daraus dann eine Objekt aus verschiedenen Objekten/Klassen zusammenbauen, die dann die entsprechenden Funktionalitäten hätten, die ich bräuchte um damit zu arbeiten. Also zumindest wenn die Aufgabe nicht ganz trivial wäre und auf diesem "Abstract Syntax Tree" supereinfach zu erledigen wäre.
Ich denke so einfach wird es (zumindest fuer mich) nicht.
Zunaechst muessen die Templates verglichen werde, d.h. es wird ein Basistemplate angegeben, welches mit allen anderen Templates in der Inputdatei verglichen wird. Das Ergebnis des Vergleichs ist die Anzahl der Key:=Value-Paaren, die in beiden Templates gleich sind. Ich denke fuer den Vergleich ist die Listendarstellung recht gut geeignet.

Darueber muss ich mir mal in den naechsten Tagen den Kopf zerbrechen.

Gruss
Gerhard
Gast

der_Gerhard hat geschrieben: Zunaechst muessen die Templates verglichen werde, d.h. es wird ein Basistemplate angegeben, welches mit allen anderen Templates in der Inputdatei verglichen wird. Das Ergebnis des Vergleichs ist die Anzahl der Key:=Value-Paaren, die in beiden Templates gleich sind. Ich denke fuer den Vergleich ist die Listendarstellung recht gut geeignet.
Hi *,

mittlerweile bin ich zu dem Schluss gekommen, dass Listen fuer den Vergleich nicht gut sind, da sie schwer handbar sind. Ich mache dies mal an einem Beispiel klar:

Code: Alles auswählen

template name typ := {
          {
            a2 :=5,
            a1 :=
            {
              b1 :=
              {
                id := localTermId1
              }
            }
          },
          {
            a1 :=
            {
              b2 :=
              {
                id := localTermId2
              }
             },
          }
}
Um nun "id" eindeutig identifizieren zu koennen, muss man sich auch die ueberliegenden Strukturen merken, also id = a1->b1->id oder a1->b2->id. Dadurch ist id eindeutig ansprechbar, was mit der Listendarstellung nicht moeglich ist.
Kann mir jemand eine Hilfestellung geben, wie ich nun eine verschachtelte Liste mit key, value Paaren in ein verschachteltes Dictionary umwandle?
Ich habe probiert, dies mit Pyparsing und dictOf anstatt Group und delimitedList zu machen, allerdings ohne Erfolg.
BlackJack

Ich kann mir immer noch nicht konkret vorstellen was Du mit den Templates anfängst. Ob es sich zum Beispiel lohnt über das Ergebnis vom Parser nochmal mit einer Funktion rüberzugehen, die eine Objekthierarchie aus den einzelnen Komponenten bastelt.

Oder eine andere Alternative wäre eine Funktion, die aus dem Parser-Ergebnis ein Dictionary aufbaut mit Einträgen wie:

{ 'a1.b1.id': localTermId1, 'a1.b2.id': localTermId2 }

Wobei ich jetzt nicht weiss: kann in beiden "Zuweisungslisten" auf der obersten Ebene auch die gleiche "Namenskette" auftauchen, also 2x 'a1.b2.id' die sich dann halt nur in der Position unterscheiden?
Antworten