Tutorial: Einfache Textmenüs mit Python

Gute Links und Tutorials könnt ihr hier posten.
lunar

@Hyperion: Wenn Du Haskell installiert hast, dann kannst Du pandoc auch mit "cabal install --user pandoc" aus den Quellen installieren. Du musst dann lediglich "~/.cabal/bin" zu $PATH hinzufügen. Aber gut, wenn pandoc das proprietäre Format von MoinMoin nicht unterstützt, ist das ohnehin egal.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ah, danke für die Antwort. Gut zu wissen, dass Haskell sein eigenes Installationswerkzeug mitbringt :-)

Hm... wenn es ein Format gäbe, bei dem die Hauptmerkmale umgewandelt würden, könnte man das zumindest als Zwischenschritt wählen.

Gibt es da evtl. einen abtrakten Syntaxbaum in einem Markdown-Parser? Wenn ja, sollte es doch nicht so schwer sein, dieses "MoinMoin"-Format zu generieren... die Elemente an sich bleiben ja gleich und auch in derselben Reihenfolge.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Man könnte in python-creole ein html2moinmoin implementieren: https://github.com/jedie/python-creole

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Jens: Ich habe ja jetzt eine Ruby-Lösung, mit der ich ganz zufrieden bin. Das dort noch fehlende kann man sicherlich noch implementieren :-)

Aber kannst Du mir nicht mal meine Frage bezüglich des Anlegens einer Seite beantworten? Ohne diese Fähigkeit nützt mir meine bisherige Arbeit nämlich gar nichts :-D
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Seite anlegen = URL eingeben, wo man die Seite erreichen soll, dann kommt ne Fehlermeldungsseite (weil die Seite ja noch nicht existiert, 404-mäßig), wo du am Ende nen Link findest: "Seite anlegen". Wenn man's weiß, ist es ganz einfach ;)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

derdon hat geschrieben:Seite anlegen = URL eingeben, wo man die Seite erreichen soll, dann kommt ne Fehlermeldungsseite (weil die Seite ja noch nicht existiert, 404-mäßig), wo du am Ende nen Link findest: "Seite anlegen". Wenn man's weiß, ist es ganz einfach ;)
Das hat Hyperion probiert. Ich schätze mal, das liegt daran dass er nicht angemeldet war. Wenn er sich einloggt, dann sollte es auch den Link geben. AFAIR.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@derdon: Danke :-)

@Leonidas: Nee, ich hatte tatsächlich nur probiert, über das Suchen der Seite an einen "Create"-Link zu kommen. So kenne ich das von MediaWikis. Angemeldet war ich schon. Ehrlich gesagt finde ich es auch doof, dass das bei MoinMoin augenscheinlich so nicht geht.

Naja, man findet das ganze jetzt unter: http://wiki.python-forum.de/Tutorial_Textmen%C3%BC
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
stielchen
User
Beiträge: 14
Registriert: Sonntag 27. Juli 2014, 09:28

Hallo Hyperion,
das ist ein sehr schönes und anschauliches Tutorial. Hat mir als Einsteiger sehr geholfen, die Idee den Inhalt von der Logik zu trennen hatte ich auch in meinem Projekt, wusste aber nicht, wie man das in Python umsetzt. Im Tutorial hast Du ganz zum Schluss noch einen Hinweis auf weitere Module (Submenüs usw.) gegeben. Wo findet man die denn? Ich möchte nun auch so ein Submenü gestalten, weiß aber nicht, ob man nun eine vollumfängliche Menü-Liste (also mit allen Elementen aller Menüs) aufbaut oder für jedes (Sub-)Menü ein eigenes.

Des weiteren möchte ich Funktionen mit dem Menü aufrufen, die Instanz-Methoden sind, d.h. ich kann doch dann die Menü-Liste erst definieren, nachdem die Instanz erstellt wurde. Gibt es da vielleicht eine bessere Lösung? Mir ist da irgendwo im Sinn, dass es sowas wie Klassen-Funktionen gibt, wo man also keine Instanz vorher erstellen muss um auf die Funktionen zuzugreifen. Bin aber nicht sicher, ob ich da auf dem richtigen Wege bin...

Viele Grüße
stielchen
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

stielchen hat geschrieben:Hallo Hyperion,
das ist ein sehr schönes und anschauliches Tutorial. Hat mir als Einsteiger sehr geholfen,
Danke, schön zu hören :-)
stielchen hat geschrieben: Im Tutorial hast Du ganz zum Schluss noch einen Hinweis auf weitere Module (Submenüs usw.) gegeben. Wo findet man die denn?
In einem Github-Repository: https://github.com/Lysander/snippets/tr ... implemenus
stielchen hat geschrieben: Des weiteren möchte ich Funktionen mit dem Menü aufrufen, die Instanz-Methoden sind, d.h. ich kann doch dann die Menü-Liste erst definieren, nachdem die Instanz erstellt wurde. Gibt es da vielleicht eine bessere Lösung? Mir ist da irgendwo im Sinn, dass es sowas wie Klassen-Funktionen gibt, wo man also keine Instanz vorher erstellen muss um auf die Funktionen zuzugreifen. Bin aber nicht sicher, ob ich da auf dem richtigen Wege bin...
Naja, es gibt Klassenmethoden, aber die haben dann eben auch keinen Zuggriff auf das Exemplar an sich ;-)

Ich fürchte da führt kein Weg drum herum; man kann sich natürlich irgend welche Wrapper bauen, die den Zugriff kapseln (``operator.methodcaller`` o.ä.), aber irgend wann muss man das Exemplar natürlich übergeben!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
stielchen
User
Beiträge: 14
Registriert: Sonntag 27. Juli 2014, 09:28

Das Beispiel aus "submenue.py" gefällt mir, habe es übernommen aber noch ein paar Anpassungen gemacht. So wird jetzt in jedem Menü eine Überschrift ausgegeben, damit man weiß wo man ist und die "Zurück"-Funktion habe ich nun fix auf Punkt 9 gelegt (viele Einträge habe ich eh nicht). So finde ich das navigieren leichter.

Aber an einem Punkt hänge ich nun fest. Einer der durch das Menü aufgerufenen Funktionen erwartet einen Parameter, der "command()"-Aufruf in Zeile 154 scheitert dann mit der Fehlermeldung:
command()
TypeError: 'NoneType' object is not callable

Irgendwie scheint er nicht zu erkennen, dass es da noch einen Parameter zu berücksichtigen gibt:
Beispiel (siehe "Python"-Zeile):

Code: Alles auswählen

menu = {
"root": (
("Hallo", hello),
("Python", python(arg)),
("Submenu", "submenu"),
("Exit", lambda: sys.exit(0))
)
BlackJack

@stielchen: *Du* rufst die Funktion `python()` auf und in dem Tupel landet dann der *Rückgabewert* dieser Funktion, der anscheinend `None` ist und sich natürlich nicht aufrufen lässt. Schau mal wie das mit dem `sys.exit()` gelöst ist.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@stielchen: Wie BlackJack schon sagte, rufst Du die Funktion auf. Das ist ja gerade der "Clou" an der ganzen Sache, dass man die Funktionsobjekte an sich als Daten auffassen kann und diese auch in Listen, Dictionaries usw. ablegen kann. Dazu darf ich diese aber nicht aufrufen! Lies Dir dazu noch mal den Abschnitt "Funktionen sind auch Objekte!" durch. Da wird der Unterschied iirc erklärt.

In der Tat gehe ich im Tutorial nicht darauf ein, wie man sich Callables erstellt, die Parameter benötigen. (Vielleicht sollte ich das bei Zeiten mal nachholen? Wobei dann noch Menüs via Dekoratoren auch noch ein Thema wären... *seufz* die liebe Zeit :mrgreen: ) Zu diesem Thema schau Dir einfach mal etwas zu ``lambda``, oder auch ``functools.partial`` an. Beides kann man gut benutzen, um benötigte Parameter *vor* dem Aufrufzeitpunkt an eine Funktion zu binden, so dass man diese beim eigentlichen Aufruf selber *nicht* mehr angeben muss. Das sind übrigens Möglichkeiten, den Command Pattern in Python umzusetzen :-)

Wo ich mir selber meinen Code noch mal angeguckt habe, folgendes würde ich heute wohl umschreiben:

Code: Alles auswählen

if isinstance(command, str):
    category = command
else:
    command()

# imho eleganter
if callable(command):
    command()
else:
    category = command
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten