python2to3

Du hast eine Idee für ein Projekt?
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
Ich habe aus Übungszwecke ein kleines Programm geschrieben, in welchem man die die Änderungen von Python2 zu Python3 dokumentieren kann und Begriffe über eine Suchfunktion wieder abrufen kann.
Ich habe es mal python2to3 genannt.

Hier https://gist.github.com/3143758 könnt Ihr es Euch anschauen und wenn Ihr wollt auch testen. :wink:

Sollte Euch etwas an meinem Code nicht gefallen, so freue ich mich auf ein Info.

Grüße Nobuddy
BlackJack

@Nobuddy: So als Info: Der Code gefällt mir nicht. Aus Gründen die aber alle schon mehr als einmal gesagt wurden…
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

@BlackJack, dachte ... da kommt auch mal was anderes, evtl was Positives. :wink:

Ist es die Art, wie der Code geschrieben ist, sind es bestimmte Codestücke ...?
BlackJack

@Nobuddy: Es wird über die globale Variable `data` kommuniziert. Das ist eigentlich schon der Punkt wo's für die Tonne ist.

Es gibt keine echten Funktionen die Argumente entgegen nehmen und ein Ergebnis zurück geben. Die „Funktion” *die* explizit etwas zurück gibt, bei der ist das total unsinnig, denn sie gibt immer `None` zurück und das wird auch nirgends ausgewertet/verwendet.

Die Programmsteuerung über den rekursiven Aufruf von `control()` ist kaputt. So etwas macht man nicht in Programmiersprachen die in der Sprachdefinition keine optimierung von Endrekursion zusagen. Wenn das nicht von der Sprache unterstützt wird, verbraucht so ein Programm ohne Not Speicher und fährt irgendwann an die Wand wenn der Aufrufstapel voll ist.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

@BlackJack, daß ich mich noch mehr mit der Materie befassen muß ist klar und mein Code hier sich auch bestimmt anderst gestalten lässt auch!
Bei mir funktioniert es zumindest so, wie ich es mir vorgestellt habe, was aber nicht heißen soll, daß es auch so perfekt ist.
Daher würde ich mich freuen, wenn Du mich etvl. hier etwas unterstützen würdest, damit ich die Unterschiede zu meinem code erkennen kann. Soll aber nicht heißen, daß Du mir jetzt Code auf dem Präsentierteller lieferst!
BlackJack hat geschrieben:@Nobuddy: Es wird über die globale Variable `data` kommuniziert. Das ist eigentlich schon der Punkt wo's für die Tonne ist.
'menucheck(infotext, infos)' ist hier ein interaktives Menü, welches über die globale Variable `data` kommuniziert.
Sollte 'data' Deiner Meinung, dann direkt an die jeweilige Funktion übergeben werden?
Beispiel:

Code: Alles auswählen

def inputlist(data):
Oder willst Du mir dami etwas anderes mitteilen?
BlackJack hat geschrieben:Es gibt keine echten Funktionen die Argumente entgegen nehmen und ein Ergebnis zurück geben. Die „Funktion” *die* explizit etwas zurück gibt, bei der ist das total unsinnig, denn sie gibt immer `None` zurück und das wird auch nirgends ausgewertet/verwendet.
Das dürfte wohl mit Deinem obigen Punkt zusammenhängen.
Die Funktion 'datasearch()' ist für die Suchergebnisse aus der erstellten Liste, die durch die Funktion 'inputlist()' erstellt wird.
Das Einzigste was ich mir vorstellen kann, ein Argument zu übergeben, wäre die globale Variable 'data'.
Hier meine ich aber, daß hier ein erheblicher Mehraufwand an Code sich ansammeln würde.
BlackJack hat geschrieben:Die Programmsteuerung über den rekursiven Aufruf von `control()` ist kaputt. So etwas macht man nicht in Programmiersprachen die in der Sprachdefinition keine optimierung von Endrekursion zusagen. Wenn das nicht von der Sprache unterstützt wird, verbraucht so ein Programm ohne Not Speicher und fährt irgendwann an die Wand wenn der Aufrufstapel voll ist.
Vielleicht könntest Du hier etwas genauer drauf eingehen, da mir das mit dem Aufrufstapel nicht klar ist?
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Ist wohl Sommerzeit ... und alle liegen am Strand ... :lol:

Um das Sommerloch auszufüllen, habe ich mal was Neues gemacht: https://gist.github.com/3169367

Vielleicht ist das eine bessere Alternative!?
Mein Problem liegt noch bei der Namensgebung, hoffe aber das auch das halbwegs akzeptabel ist. :wink:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nobuddy hat geschrieben:Ist wohl Sommerzeit ... und alle liegen am Strand ... :lol:
Schön wärs ;-)

Ich verweise mal auf mein Textmenü-Tutorial - das trifft es hier zwar nicht exakt, aber da lernst Du einige Zusammenhänge bezüglich der Organisation von Daten und Funktionen. Ich denke damit könnte man da einiges aufgeräumter gestalten.

Ich gebe zu, dass ich mir das nicht sehr intensiv angeguckt habe. Allerdings sah ich ein `global` - insofern ist da noch etwas stark verbesserungsbedürftig :-P

BTW: Die Datei `pythoninfo.txt` fehlt - bei gist.github.com kannst DU *mehrere* Dateien pro Gist hochladen. Evtl. fügst Du die noch mal nach?

Zudem sehe ich da wieder einmal eine ungewollte Rekursion - auch wenn Du das dieses Mal versuchst, via `return` zu "reparieren". Generell ist das kein schöner Ansatz und zudem vermutlich leicht zu vermeiden.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Ja, den Letzten beißen immer die Hunde ... :wink:

Danke für Dein Textmenü-Tutorial, dies sieht viel versprechend aus. Werde mich da mal durch arbeiten und bestimmt lässt sich mein Code aufgeräumter gestalten.

Meine Idee war, ein interaktives Menü zu erstellen, das wie eine 'Eier legende Wollmilchsau' funktioniert.
Die Funktion 'interaktiv_menu' funktioniert nach dem Prinzip, ein mehrspaltiges Auswahlmenü sowie auch ein 'Ja/nein-Menü' auszugeben und die Eingaben entsprechend zu verarbeiten. Diese Funktion funktioniert wirklich prima.
Allerdings muß ich eingestehen, daß es für einen Außen stehenden, sehr schwer ist die Funktion und der Ablauf nachzuvollziehen, was nicht sein sollte.
Ich habe eine sehr abstrakte und wahrscheinlich auch zu komplizierte Denkweise, was sich immer wieder in meinem Code wieder spiegelt.
Daher wird es für mich ein langer Weg werden, dies zu ändern und wie hier das Textmenü-Tutorial von Dir, hilft da sehr.

Schreibe weiter solche Tutorialś! :wink:

Als ich das 'global' eingesetzt habe, wußte ich daß es anderst gehen sollte, aber fehlte die zündete Idee.
Auch das mit der Rekursion, ist auch so ein Indiz, daß ich noch viel zu lernen habe.

Habe hier https://gist.github.com/3174882 nochmals die aktuelle Version mit `pythoninfo.txt`.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nobuddy hat geschrieben: Als ich das 'global' eingesetzt habe, wußte ich daß es anderst gehen sollte, aber fehlte die zündete Idee.
Na das hatten wir doch schon so oft. Du musst einfach das Objekt als Parameter an die anderen Funktionen weiterreichen, die auch auf dieses Objekt angewiesen sind. So einfach ist das eigentlich...
Nobuddy hat geschrieben: Auch das mit der Rekursion, ist auch so ein Indiz, daß ich noch viel zu lernen habe.
Naja, Du darfst eben nicht Funktionen wechselseitig aufrufen wie Du es bei `start` und `interactive_menu` tust! Immer wenn Du so etwas machst, erzeugst Du eine Rekursion. Stattdessen rufe einfach aus `start` nur `interactive_menu` auf und kehre von dort *immer* nach `start` zurück. Dann kann das von neuem losgehen. Das kann man in der Ausgangsfunktion prima mit einer Endlosschleife lösen:

Code: Alles auswählen

while True:
    # hier Aufrufe zu anderen Funktionen
    # ggf. irgend eine Benutzerabfrage / spezieller Rückgabewert o.ä.,
    # um mittels `break` aus der Schleife zu springen
Ich mache das bei meiner Menüfunktion genauso. Letztlich funktionieren alle Programme, die auf Dauer wiederholt etwas machen, derartig. Bei GUIs gibt es z.B. auch so einen "Eventloop" - sonst würde eine GUI nur kurz aufpoppen und sich dann wieder sofort schließen ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hyperion, Danke für Deine Hinweise.

Dein Textmenü-Tutorial ist wirklich Gold wert und wenn ich den Abschluß-Code betrachte, sieht das richtig schön aufgeräumt und stimmig aus. Ich werde hier eine Weile im Textmenü-Tutorial verbleiben, bis mir alles klar geworden ist.
Dann dürfte auch das Umsetzen auf mein python2to3, kein Problem mehr sein. :wink:
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wobei ich bei der Endfassung des Codes aus Hyperions Tutorial in Zeile 22 ja nach wie vor über das `print("{} {}".format(index, item[0]))` stolpere. Das kann man via `print(index, item[0], sep=' ')` IMHO etwas unkomplizierter schreiben.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

@snafu, ich meine daß `print("{} {}".format(index, item[0]))` bekannter und besser zu verstehen ist, für mich zumindest.
Wenn einem das `print(index, item[0], sep=' ')` geläufig ist, ist es klar kürzer. :wink:

Ich habe das Menu aus Hyperionś Textmenü-Tutorial verwendet: https://gist.github.com/3182167

Bei der Funktion handle_menu, habe ich ein try/except eingebaut. Damit kommt auch keine Fehlermeldung mehr bei Eingabe von Buchstaben oder einer leeren Enter-Eingabe.

Code: Alles auswählen

def handle_menu(menu):
    while True:
        print('\n<<< Hauptmenü >>>')
        for index, item in enumerate(menu, 1):
            print("{}  {}".format(index, item[0]))
        try:
            choice = int(input("Nummer: ")) - 1
            if 0 <= choice < len(menu):
                menu[choice][1]()
            else:
                print("\nBitte nur Zahlen im Bereich 1 - {} eingeben\n".format(
                                                                    len(menu)))
        except ValueError:
            print("\nBitte nur Zahlen im Bereich 1 - {} eingeben\n".format(
                                                                    len(menu)))
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Code: Alles auswählen

def handle_menu(menu):
    while True:
        print('\n<<< Hauptmenü >>>')
        for index, item in enumerate(menu, 1):
            print("{}  {}".format(index, item[0]))
        try:
            choice = int(input("Nummer: ")) - 1
            menu[choice][1]()
        except (ValueError, IndexError):
            print("\nBitte nur Zahlen im Bereich 1 - {} eingeben\n".format(
                                                                    len(menu)))
Das Leben ist wie ein Tennisball.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

@EyDu, Danke für den Hinweis.
Der IndexError ist bei meiner Fehlermeldung nicht aufgetreten, werde den Eintrag aber entsprechend ändern.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du solltest dir die Änderung schon genauer anschauen. Der IndexError konnte bei dir nicht geworfen werden, ich umgehe damit nur das zusätzliche if/else. Es wäre aber insgesamt aber wohl klüger die Ausführung der Funktion aus dem try-Block zu ziehen, sonst hast du vielleicht Probleme mit Fehlern aus den Unterfunktionen, welche sich dann hübsch verstecken würden.

Code: Alles auswählen

def handle_menu(menu):
    while True:
        print('\n<<< Hauptmenü >>>')
        for index, item in enumerate(menu, 1):
            print("{}  {}".format(index, item[0]))
        try:
            choice = int(input("Nummer: ")) - 1
            func = menu[choice][1]
        except (ValueError, IndexError):
            print("\nBitte nur Zahlen im Bereich 1 - {} eingeben\n".format(
                                                                    len(menu)))
        else:
            func()
Das Leben ist wie ein Tennisball.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

@EyDu, Danke nochmals für Deinen Hinweis, das hatte ich glatt übersehen.
Wie einfach das Leben doch sein kann ... :wink:
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Ich habe ein Problem mit 'globalen', das ich gerne vermeiden möchte, mir aber bisher die zündende Idee fehlt.
Als Grundlage verwende ich das Textmenü, aus dem Textmenü-Tutorial von Hyperion.

Die Funktion zum Menüpunkt 'Eintrag suchen', sieht so aus:

Code: Alles auswählen

nameline = 'Nummer', 'Python2', 'Python3', 'Info'

def search_entry():
    nl0 = len(nameline[1])
    nl1 = len(nameline[2])
    while True:
        entry = input('\nSuchbegriff: ')
        if entry:
            print("\nEintrag wird gesucht")
            with open(datapool, 'r') as infile:
                reader = csv.reader(infile, delimiter="\t", quotechar="^")
                global dataline
                dataline = list()
                r0 = set()
                r1 = set()
                global counter
                counter = 0
                for row in reader:
                    if row[0] == entry:
                        counter += 1
                        r0.add(len(row[0]))
                        r1.add(len(row[1]))
                        data = counter, row[0], row[1], row[2]
                        dataline.append(data)
                    elif entry in str(row):
                        counter += 1
                        r0.add(len(row[0]))
                        r1.add(len(row[1]))
                        data = counter, row[0], row[1], row[2]
                        dataline.append(data)
            if counter == 0:
                print('\nEs liegen keine Ergebnisse zu Ihrem Suchbegriff %s vor\n' % entry)
                break
            elif counter > 0:
                print('\n-----\n{}:\t{}:{}{}:{}{}:'.format(nameline[0], nameline[1], ' ' * (4 + (max(r0) - nl0)), nameline[2], ' ' * (4 + (max(r1) - nl1)), nameline[3]))
                for row in dataline:
                    print('{}\t{}{}{}{}{}\n'.format(row[0], row[1], ' ' * (max(r0) - len(row[1]) + 5), row[2], ' ' * (max(r1) - len(row[2]) + 5), row[3]))
                print('-----')
                break
Hoffe, es sieht nicht zu abenteuerlich für Euch aus.
Ich wollte die Ausgabe in einem bestimmten Format ausgeben. Die oberste Zeile sollte die Spaltenbenennung beinhalten. Die Ausgabezeilen mit Daten, sollten genau vertikal mit der Spaltenbenennung übereinstimmen.
Den Parameter 'nameline', habe ich bewußt global gesetzt, um später aus verschiedenen Funktionen, darauf zugreifen zu können.
Ich weiß ... 'global' ..., das stört mich selbst, aber zuerst möchte ich Euch den Zusammenhang nahe bringen! :wink:

Nun habe ich mir gedacht, daß diese Funktion 'search_entry()' auch für den Menüpunkt 'Eintrag ändern' verwendet werden kann, um doppelten Code zu vermeiden.
Dazu sieht die Funktion 'load()' zu dem Menüpunkt 'Eintrag ändern' folgendermaßen aus (ist aber noch nicht fertig!):

Code: Alles auswählen

def load():
    search_entry()
    while True:
        try:
            selection = int(input('Zeilennummer: '))
            if int(1 <= selection <= counter):
                for row in dataline:
                    if selection == row[0]:
                        print("\nDatensatz wird geladen\n")
                        chanceline = row[1:]
                        print(chanceline)
                break
            else:
                print('Falsche Eingabe, bitte wählen Sie eine Zahl von 1 bis %s aus!' % counter)
        except (ValueError, IndexError):
            print('Falsche Eingabe, bitte wählen Sie eine Zahl von 1 bis %s aus!' % counter)
            break
Ich brauche (im Moment noch) die zwei 'globalś' für diese Funktion.

Nun wenn ich das richtig verstanden habe, soll Rekursion vermieden werden!
In meinem Beispiel rufe das Hauptmenü 'handle_menu(menu)' auf, wähle dort einen Menüpunkt bei der die zugehörige Funktion, einen vordefinierten Ablauf durchgeht und am Ende wieder zum Hauptmenü zurückkehrt.

Um doppelten Code zu vermeiden, nutze ich also in der Funktion 'load()', die Funktion 'search_entry()' mit und benötige aus 'search_entry()' zwei Parameter.
Wie kann ich das umsetzen, ohne wieder eine Rekursion zu verwenden?
Zuletzt geändert von Nobuddy am Freitag 27. Juli 2012, 17:39, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Es wurde dir doch jetzt schon mehrfach gesagt: wenn du globals hast, dann löst du diese durch Parameter bei den Funktionen und Rückgabewerte auf. Das muss man natürlich ggf. über mehrere Aufrufstufen machen. Das ist aber nun wirklich einer der Grundlagen überhaupt. Bevor das Problem nicht gelöst ist, lohnt es sich gar nicht auf deinen Code zu schauen.
Das Leben ist wie ein Tennisball.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

snafu hat geschrieben:Das kann man via `print(index, item[0], sep=' ')` IMHO etwas unkomplizierter schreiben.
Ja, da hast Du wohl recht. Bin da noch nicht so sehr in Python3 drin gewesen... sollte ich vielleicht noch mal ändern. Oder Du änderst es direkt im wiki - größere Änderungen sind ja eigentlich nicht mehr zu erwarten und daher auch keine Konvertierung aus Github nötig.

Ich sollte auch mal mein Konverterscript in Ruby bei Github reinstellen btw...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nobuddy hat geschrieben: Nun wenn ich das richtig verstanden habe, soll Rekursion vermieden werden!
In meinem Beispiel rufe das Hauptmenü 'handle_menu(menu)' auf, wähle dort einen Menüpunkt bei der die zugehörige Funktion, einen vordefinierten Ablauf durchgeht und am Ende wieder zum Hauptmenü zurückkehrt.
Was ist denn Dein "Hauptmenü"? Gib doch mal ein vereinfachtes Code-Fragment in dem man die Aufrufhierarchie sehen kann!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten