Warum ist die Liste leer ?

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.
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

ok, danke, habe ich ja verstanden...
wenn ich nun

Code: Alles auswählen

#!/usr/bin/env python3

def fkt_1(string):
    print(string)


if __name__ == '__main__':
    while True:
        fkt_1('hallo')
schreibe, dann bekomme ich eine Endlosschleife. WARUM ?
Python sagt doch:

Code: Alles auswählen

>>> True is None
False
>>> True == None
False
>>> 
meine Frage:
__main__ ist ja sozusagen "abgearbeitet" (letzte Zeile ist ausgeführt). Durch *while True* 'sitzt' es aber in einer Schleife fest, und sollte(?), da beispielsweise kein *break* oder kein anderer nachfolgender Code vorhanden ist, wieder von Vorne (Code, erste Zeile) anfangen, oder ?.
Aber es (__main__) bekommt doch von *fkt_1* ein *None* zurück. warum dann die Endlosschleife ?
Ich rufe doch über __main__ die Funktion *fkt_1* auf, die den (internen) Rückgabewert *None* liefert !
wenn ich stattdessen

Code: Alles auswählen

#!/usr/bin/env python3

def fkt_1(string):
    print(string)
    string = None


if __name__ == '__main__':
    while string:
        fkt_1('hallo')
bekomme ich einen Error, der mir auch bewußt ist:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Program Files\Python37\scripts\vorlage_neu.py", line 8, in <module>
    while string:
NameError: name 'string' is not defined
ich hoffe, ich konnte mich gut genug ausdücken.
warum bekomme ich eine Endlosschleife mit folgendem Code ?

Code: Alles auswählen

#!/usr/bin/env python3

def fkt_1(string):
    print(string)
    return None


if __name__ == '__main__':
    while True:
        fkt_1('hallo')
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
damit verwirrst du mich nicht im geringesten. DAS verstehe ich sogar sehr gut !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13102
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Warum solltest Du bei ``while True:`` *keine* Endlosschleife bekommen? Genau so schreibt man doch eine Endlosschleife. Und solange *im* Schleifenkörper nichts steht was selbigen verlassen könnte, rennt die endlos. Der Schleifenkörper wird immer wieder ausgeführt solange der Ausdruck zwischen ``while`` und dem ``:`` ”wahr” ist. Und da steht `True`. Also ”wahr”. `True` ist immer ”wahr”, per Definition, das ändert sich *nie*, also wird der Schleifenkörper *immer* ausgeführt.

Was irgendwelche Funktionen im Schleifenkörper als Rückgabewert haben, hat keinen Einfluss auf den Wahrheitsgehalt von `True`. Aus der Schleife kommt man nur mit ``break``, oder innerhalb von Funktionen/Methoden mit ``return``, und natürlich mit Ausnahmen heraus.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
ich habe dadurch wieder einen Schritt nach vorne gemacht, danke !

EDIT:
und ich dacht die ganze Zeit, dass der Rückgabewert dies beeinflussen würde ...

EDIT 2
bezugnehmend auf mein Chart-Script würde dies dann doch auch bedeuten, dass ich, um ein Benutzermenue nach jeder Funktion/Methode wieder "erscheinen" lassen zu können, dies *nur* durch den Aufruf der Funktion "Zeige Benutzermenu an" bewerkstelligen kann, da man Code ja nicht wiederholen und somit in einer Funktion/Methode *auslagern*(?) sollte ...
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13102
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: EDIT 2 verstehe ich nicht so ganz. Das sollte doch jetzt so funktionieren, und ich sehe auch keine Codewiederholung im Quelltext die man beseitigen müsste‽
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
darum geht's eigentlich :
1. Mein Post vom Donnerstag 21. Februar 2019, 21:25:
2. Antwort von Sirius3:
Zeile 60/90/107/145: Funktionen sind keine Sprungmarken. Einfach die Funktion zurückkehren lassen.
3. Mein Post vom Freitag 22. Februar 2019, 00:03

=> ich habe mit dem Begriff 'Sprungmarken' nicht angefangen, und jeder ist halt darauf eingestiegen, wahrscheinlich, weil ich sie im Kontext falsch verwendet habe ...
=> auf mein Post vom Freitag 22. Februar 2019, 00:03 habe ich keine konkrete Antwort bekommen (return main(), etc.)
=> es hat bereits vorher funktioniert (sofern ich das beurteilen kann), dann kam das Thema mit den Sprungmarken auf ...

ich bin momentan generell wieder etwas verunsichert. In Python geht es ja u.a. um die schrittweise Verfeinerung, d.h. auch Code, der beispielsweise doppelt ist, in Funktionen/Methoden 'auszulagern' (falscher Begriff ?), etc.. Ob diese Funktionen/Methoden etwas zurückliefern, sei jetzt mal nicht so wichtig. Um aber nun diese (ausgelagerten) Funktionen/Methoden 'ans Laufen' zu bringen, muss ich sie doch in der jeweils anderen Funktion (aus der sie ausgelagert wurden) aufrufen.

Beispielsweise:

Code: Alles auswählen

def charteintraege_loeschen(charts, auswahl):
    while True:
        print('*** Einträge löschen ***')
##        print(charts)                                     #44: Debugging   
        chartliste_anzeigen(charts, auswahl)
        delete = input('Gebe die Platznummer des zu löschenden Eintrags ein :  ')  #46: eval() oder int() verursachen ValueError (int ... base 10)
        if not delete:                                     #47 zu #46: erlaubte Eingaben: natürliche Zahlen >= 1 bis *len(charts)*
            break                                           #48: als Einzeiler schreiben ?
        try:
            delete = int(delete) -1                            #50: siehe #46
            if delete < 0 or delete >= len(charts):    #51: erlaubte Eingaben: natürliche Zahlen >= 1 bis *len(charts)*
                print('Diese Eingabe ist ungültig !')
                break
            del charts[delete]
            print('Der Eintrag wurde soeben gelöscht !')
        except (IndexError, ValueError, TypeError):
            print('Diese Eingabe ist ungültig !')
            break                                           #58: bei der Verwendung von 'continue': speichert bei fehlerhaften Eingaben (delete < 1)

        charteintraege_speichern(charts)
    return main()


def charteintraege_modifizieren(charts, auswahl):
    while True:
        print('*** Einträge ändern ***')
##        print(charts)                                     #67: Debugging
        chartliste_anzeigen(charts, auswahl)
        modify = input('Gebe die Platznummer des zu ändernden Eintrags ein :  ')   #69: eval() oder int() verursachen Error
        if not modify:                                     #70 Nachtrag zu #69: ValueError: invalid literal for int() with base 10: ''
            break
        try:
            modify = int(modify) -1                         #73: siehe #69; Zuweisung wegen Indizierung [Index -1]
            if modify < 0 or modify >= len(charts):
                print('Diese Eingabe ist ungültig !')
                break
        except (IndexError, ValueError, TypeError):
            print('Diese Eingabe ist ungültig !')
            break                                           #79: bei Verwendung von 'continue': speichert bei fehlerhaften Eingaben (modify < 1)
        stimme_neu = charts[modify][0]                      ## TO DO: ohne Indexing lösen ?!
        titel_neu = input('trage den zu ändernden Titel ein, ansonsten [Enter] :  ')
        if not titel_neu:                                  #82: als Einzeiler schreiben ?
            titel_neu = charts[modify][1]                   ## TO DO: ohne Indexing lösen ?!
        print('neuer Titel:', titel_neu)
        interpret_neu = input('trage den zu ändernden Interpreten ein, ansonsten [Enter] :  ')
        if not interpret_neu:                              #86: als Einzeiler schreiben ?
            interpret_neu = charts[modify][2]               ## TO DO: ohne Indexing lösen ?!
        print('neuer Interpret:', titel_neu)
        charts[modify] = (stimme_neu, titel_neu, interpret_neu) #89: Klammern sind unnötig, dienen der Lesbarkeit
        charteintraege_speichern(charts)
    return main()                                                  #91: nötig, da sonst Programm beendet wird
haben diese beiden Funktionen stellenweise ähnliche/gleiche Code-Zeilen. Würde ich diese jetzt in einer separaten Funktion/Methode 'auslagern', dann müßte ich diese ausgelagerte Funktion doch jeweils von den beiden anderen Funktionen aufrufen ... (dann kam das Thema 'Sprungmarken' auf ...)
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13102
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Bei den beiden Funktion ist das ``return main()`` am Ende auf jeden Fall falsch. Wenn das weg ist, dann kehrt der Programmablauf am Ende zum Aufrufer zurück und zwar mit beenden der jeweiligen Funktion und Freigabe der nicht mehr benötigten lokalen Variablen und auch der Verwaltungsinformation die nötig ist um sich zu merken an welche Stelle im Code zurückgekehrt werden muss. Das mag erst einmal so aussehen als würde das so funktionieren, aber wie gesagt gibt es da ein Ende. Man kann das nicht beliebig oft machen. Irgendwann gibt es einen `RecursionError` und das Programm bricht einfach ab.

Was da bei Kommentar #91 steht, stimmt ja nur wenn beim Aufrufer oder dessen Aufrufer oder …, nicht dafür gesorgt wird, dass das Programm nicht abbricht, sondern weiterläuft.

Und ja, in diesem beiden Funktionen ist Code der so ähnlich ist, das er ein allgemeineres Problem löst, was man in eine eigene Funktion auslagern kann. Beispielsweise die Auswahl eines Datensatzes passiert in beiden Funktionen mit fast identischem Code.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
es leuchtet mir ein, daß *return main()* definitv falsch ist. Wenn ich nach den Funktionen aber wieder das Benutzermenu einblenden möchte, dann muss ich doch anstelle von *return main()* *main()* schreiben (womit wir wieder beiim Begriff 'Sprungmarken' angelangt wären.)
hier der Code OHNE main() am Ende der Funktionen "charteintraege_loeschen", "charteintraege_modifizieren", "chartliste_erweitern" und "chartliste_anzeigen" ... ich habe sie kommentiert, damit es einfacher ist, die Vergleiche zu sehen (dann natürlich einfach wieder entkommentieren) => es reicht zum Probieren aus, im Auswahlmenu nur *a* zu drücken (=> kein Auswahlmenu mehr)

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Verwalten einer Chartliste
     => Unterverzeichnis 'data' anlegen
     => Unterverzeichnis 'tmp' anlegen """

__author__ = 'Perlchamp'
__date__ = '21.02.2019'

import pickle


CHARTS_FILENAME = 'data/charts.dmp'
BACKUP_FILENAME = 'tmp/charts.dmp'
MENUE_WIDTH = 30                                            #15: zu viele Konstanten ?
SPALTE_TITEL = 35
SPALTE_INTERPRET = 36
SPALTE_STIMMEN = 11
CHART_ANZEIGE = 103
MENUE_ANZEIGE = 60
CHART_VORSCHUB_01 = ' ' *3
CHART_VORSCHUB_10 = ' ' *2
CHART_VORSCHUB_100 = ' ' *1
MENUE_VORSCHUB = ' ' *6


def chartliste_laden() :
    try:
        with open(CHARTS_FILENAME, 'rb') as file:
            charts = pickle.load(file)
##        print(charts)                                     #31: Debugging
    except (FileNotFoundError, EOFError):                  #32: charts.dmp ist leer oder nicht vorhanden
        print('leere Liste !')
        charts = list()                   
##    except EOFError as error :                            #35: keine Erklärung darüber im Netz gefunden !
##        print("Entschuldigung\nDer Chart-Manager musste beendet werden.\nGrund :  ")
 
    return charts


def charteintraege_loeschen(charts, auswahl):
    while True:
        print('*** Einträge löschen ***')
##        print(charts)                                     #44: Debugging   
        chartliste_anzeigen(charts, auswahl)
        delete = input('Gebe die Platznummer des zu löschenden Eintrags ein :  ')  #46: eval() oder int() verursachen ValueError (int ... base 10)
        if not delete:                                     #47 zu #46: erlaubte Eingaben: natürliche Zahlen >= 1 bis *len(charts)*
            break                                           #48: als Einzeiler schreiben ?
        try:
            delete = int(delete) -1                            #50: siehe #46
            if delete < 0 or delete >= len(charts):    #51: erlaubte Eingaben: natürliche Zahlen >= 1 bis *len(charts)*
                print('Diese Eingabe ist ungültig !')
                break
            del charts[delete]
            print('Der Eintrag wurde soeben gelöscht !')
        except (IndexError, ValueError, TypeError):
            print('Diese Eingabe ist ungültig !')
            break                                           #58: bei der Verwendung von 'continue': speichert bei fehlerhaften Eingaben (delete < 1)

        charteintraege_speichern(charts)
##    main()


def charteintraege_modifizieren(charts, auswahl):
    while True:
        print('*** Einträge ändern ***')
##        print(charts)                                     #67: Debugging
        chartliste_anzeigen(charts, auswahl)
        modify = input('Gebe die Platznummer des zu ändernden Eintrags ein :  ')   #69: eval() oder int() verursachen Error
        if not modify:                                     #70 Nachtrag zu #69: ValueError: invalid literal for int() with base 10: ''
            break
        try:
            modify = int(modify) -1                         #73: siehe #69; Zuweisung wegen Indizierung [Index -1]
            if modify < 0 or modify >= len(charts):
                print('Diese Eingabe ist ungültig !')
                break
        except (IndexError, ValueError, TypeError):
            print('Diese Eingabe ist ungültig !')
            break                                           #79: bei Verwendung von 'continue': speichert bei fehlerhaften Eingaben (modify < 1)
        stimme_neu = charts[modify][0]                      ## TO DO: ohne Indexing lösen ?!
        titel_neu = input('trage den zu ändernden Titel ein, ansonsten [Enter] :  ')
        if not titel_neu:                                  #82: als Einzeiler schreiben ?
            titel_neu = charts[modify][1]                   ## TO DO: ohne Indexing lösen ?!
        print('neuer Titel:', titel_neu)
        interpret_neu = input('trage den zu ändernden Interpreten ein, ansonsten [Enter] :  ')
        if not interpret_neu:                              #86: als Einzeiler schreiben ?
            interpret_neu = charts[modify][2]               ## TO DO: ohne Indexing lösen ?!
        print('neuer Interpret:', titel_neu)
        charts[modify] = (stimme_neu, titel_neu, interpret_neu) #89: Klammern sind unnötig, dienen der Lesbarkeit
        charteintraege_speichern(charts)
##    main()                                                  #91: nötig, da sonst Programm beendet wird
    

def chartliste_erweitern(charts):
    print('*** Einträge hinzufügen ***')
    print('Abbrechen mit der [Enter]-Taste ohne Eingabe !')
    while True:
        titel = input('Titel : ')
        if not titel:
            break
        interpret = input('Interpret : ')
        if not interpret:
            break
        charts.append((0, titel, interpret))
        charteintraege_speichern(charts)
        print('\nVielen Dank. Die aktuellen Einträge sind in der Liste gespeichert !')
    print('Abbruch: in die Liste wurde nichts eingetragen !')
##    main()
        

def charteintraege_speichern(charts):
    try:
        with open(CHARTS_FILENAME, 'wb') as file:
            pickle.dump(charts, file)
        print('Die Daten wurden soeben gespeichert !')
    except FileNotFoundError:
        print('Die Liste konnte nicht gespeichert werden !')
        
    finally:
        with open(BACKUP_FILENAME, 'wb') as backup:
            pickle.dump(charts, backup)
        print("Es wurde erfolgreich eine BackUp-Datei im Ordner 'tmp' angelegt !") #122 print()-Anweisung überhaupt ausgeben ?


def chartliste_anzeigen(charts, auswahl):
    print('-' * (CHART_ANZEIGE))
    print('chartliste'.upper().center(CHART_ANZEIGE))
    print('-' * (CHART_ANZEIGE))
##    print('Liste \'Charts\':', charts)                      #129 Debugging
    charts.sort(reverse=True)                               #Liste absteigend nach Anzahl der Votings sortieren
    for platz, (voting, titel, interpret) in enumerate(charts):
        zeile_tabelle = f'{platz+1}: {titel:<{SPALTE_TITEL}} von: {interpret:<{SPALTE_INTERPRET}}{voting:>{SPALTE_STIMMEN}} Stimmen'
        if platz < 9:
            print(f'{CHART_VORSCHUB_01}' + zeile_tabelle)
        elif platz < 99:
            print(f'{CHART_VORSCHUB_10}' + zeile_tabelle)
        else:
            print(f'{CHART_VORSCHUB_100}' + zeile_tabelle)
    print('-' * (CHART_ANZEIGE) + '\n\n')
##    if auswahl not in 'lm':                                #140: beim Löschen (l) und Modifizieren (m) bitte keine Menu-Auswahl anzeigen
##        main()

def main():
    print('-' * (MENUE_ANZEIGE))
    print('MENUE'.center(MENUE_ANZEIGE))
    print('-' * (MENUE_ANZEIGE))
    print(f'{MENUE_VORSCHUB}(A)nzeige der kompletten Chartliste')
    print(f'{MENUE_VORSCHUB}(H)inzufügen neuer Einträge')
    print(f'{MENUE_VORSCHUB}(L)öschen von Einträgen in der Chartliste')
    print(f'{MENUE_VORSCHUB}(M)odifizieren von Einträgen in der Chartliste')
    print(f'{MENUE_VORSCHUB}(E)nde des Chart-Managers')
    print('-' * (MENUE_ANZEIGE) + '\n')
    while True:
        charts = chartliste_laden()                         #154: ! charts nicht mehr eine leere Liste !
        auswahl = input('Treffen Sie eine Auswahl :  ').lower()
        if auswahl == 'e':
            print('Danke, dass Sie den Chart-Manager benutzt haben.')
            break
        elif auswahl == 'a':
            chartliste_anzeigen(charts, auswahl)
        elif auswahl == 'h':
            chartliste_erweitern(charts)
        elif auswahl == 'l':
            charteintraege_loeschen(charts, auswahl)
        elif auswahl == 'm':
            charteintraege_modifizieren(charts, auswahl)
        else :
            print('falsche Auswahl !')

        return auswahl
        
    
if __name__ == '__main__' :
    main()
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Dein Problem ist nur, dass in `main` ein `return` steht, das so keinen Sinn ergibt.
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ Sirius3:
ja, ich habe mich auch gerade gefragt ... was das hier zu suchen hat. Das Programm läuft damit trotzdem, aber klar, es muß weg.
ABER:
die von dir *bemängelten* sog. 'Sprungmarken' sind ja noch da (Zeilennummern habe ich im Vergleich zu deinem Post angepaßt)
Zeile 61/91/108/142: Funktionen sind keine Sprungmarken. Einfach die Funktion zurückkehren lassen.
Wie kann ich dieses 'Problem' denn lösen, Sirius3 ?
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13102
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Du möchtest vielleicht über die Position der ``while``-Schleife in Deiner `main()`-Funktion nachdenken. Wenn die Ausgabe der Menüpunkte wiederholt passieren soll, dann muss das halt auch *in* der Schleife stehen, und nicht *davor*.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_:
ich werde mir mal meine Gedanken machen. Vielen lieben Dank jedenfalls für eure Zeit, Geduld und Mühe mit mir !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Antworten