Neuling sucht Hilfe bei Fehlersuche

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.
Antworten
Dogy007
User
Beiträge: 2
Registriert: Dienstag 27. September 2016, 03:24

Hallo Python Freunde

Ich bin gerade dabei eine Informatik Ausbildung zu machen, und ein wenig auf den Geschmack gekommen mit Python zu arbeiten.

Gerade schreibe ich an einem "Login script".

Der Fehler ist : Wenn wähle das ich noch nicht Registriert bin und danach Erfolgreich eine Registration Abschliesse findet es Anschliessend den Neu Erstellten Benutzer nicht und gibt den Fehler "Benutzername falsch oder nicht Registriert" Aus. Vielleicht ist ja von euch jemand schlauer als ich =)

Im Moment möchte ich wirklich nur diesen Fehler beheben, auch wenn man bestimmt auch viele andere Dinge daran verbessern könnte :roll: .

Hier der Code:
https://repl.it/DiM4/0


Vielen Dank schonmal für Eure Hilfe :D
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dogy007: Du hast das falsche Vorgehen. Bevor Du den Fehler finden kannst, solltest Du Deinen Code aufräumen, denn so wie er jetzt aussieht, will und kann fast niemand irgendwelche Fehler finden.

Zuerst die generellen Dinge: Kommentare, die ganz weit rechts am Ende der Zeile stehen, sind schlecht zu lesen und werden auch leicht übersehen. Zudem machen sie die Zeilen viel zu lange. Die maximale Zeilenlänge sollte irgendwo zwischen 79 und 100 Zeichen liegen.
Explizite Vergleiche mit True oder False sind unnötig. Also einfach "while novalidlogin:" oder "while not validregistration:".
Für mich sind das irgendwie zu viele Flags, die auch noch alle ganz am Anfang auf einen Wert gesetzt werden, wo sie dann gar nicht verwendet werden. Variableninitialisierung sollte so nahe am Einsatzort wie möglich geschehen. Die Datenstruktur für proofedlogins ist etwas ungünstig. Passend wäre ein Wörterbuch das direkt Benutzernamen auf Passwörter abbildet, dann wäre das Suchen und Finden auch viel einfacher.
Apropos Suchen und Finden, das wird an mehreren Stellen verwendet und nicht nur deshalb solltest Du Funktionen definieren. Wenn der Code bis zu 7 Ebenen hat und länger ist als eine Handvoll Zeilen, ist das ein deutliches Zeichen, dass man ihn durch Funktionen besser strukturieren sollte. Man kann einfach nicht den Überblick über so verschachtelten Code behalten.

All die angesprochenen Punkte sind nicht einfach nur Nice-To-Have, sondern helfen dabei fehlerfreien, testbaren und verständlichen Code zu schreiben; nur so kannst Du Deinen Fehler finden.
BlackJack

@Dogy007: Um das mit dem aufteilen in kleinere Teilprobleme die mit Funktionen gelöst werden noch mal zu bekräftigen: Das macht den Code nicht nur verständlicher sondern Du kannst dann die einzelnen Teillösungen auch viel einfacher einzeln und isoliert testen um Fehlern auf die Spur zu kommen. Wenn der Teil mit der Registrierung nicht in diesem riesigen Codeklumpen stecken würde, könntest Du den Teil einfach separat aufrufen und schauen ob danach die entsprechenden Daten in der ”Datenbank” stehen wie Du das erwartest. Tun sie das nicht, dann weist Du, das mit der Registrierung was nicht stimmt. Falls die Daten aber okay sind, dann weist Du, das der Fehler bei der Anmeldung liegen muss. Dann kannst Du entsprechend Deine Fehlersuche auf einen der beiden Programmteile konzentrieren.

Zum grundsätzlichen Programmablauf: Der ist unsicherer als er sein müsste. Achte mal auf echte Anmeldedialoge: Die fragen immer Benutzer *und* Passwort ab und prüfen erst *dann* ob der Benutzer vorhanden ist und das Passwort zu dem Benutzer passt. Sie verraten bei einem Fehlschlag aber nicht welche der beiden Bedingungen nicht zutraf. Das verrät Angreifern nämlich ob sie den Benutzer richtig geraten haben, und zu dem nur noch das Passwort erraten müssen. Oder Angreifer können einfach erst einmal nur mit einer Liste von potentiellen Benutzernamen prüfen ob es die gibt. Und so beispielsweise erkunden ob die nach einem bestimmten Muster vergeben werden wie 'vorname.nachname' und wissen auf die Weise auch schon die Benutzernamen von künftigen Benutzern wenn sie deren Namen herausbekommen können.
BlackJack

@Dogy007: Ich habe das gerade mal auf eine handvoll Funktionen verteilt implementiert und es ist dabei dann kein einziges `True`/`False`-Flag mehr übrig geblieben. Die wird man recht einfach los in dem man ”Endlosschleifen” schreibt (``while True:``) und die dann an der entsprechenden Stelle mit ``break`` oder ``return`` verlässt.

Es ist noch ein Flag übrig, dass allerdings in einen anderen Wert ”eingeflossen” ist: zwei Funktionen geben entweder einen Benutzer (Wörterbuch mit Name und Passwort) oder `None` zurück. Nämlich die Funktion um einen Benutzer anhand des Namens heraus zu suchen und die Anmeldefunktion.
Dogy007
User
Beiträge: 2
Registriert: Dienstag 27. September 2016, 03:24

Vielen dank Erstmal für deine Rückmeldung

Ich war ja schon überglücklich das überhaupt irgendetwas funktioniert hat ;)
weiss leider nicht genau wie ich diese "Flags" am anfang loswerden soll. :(
Versuche jetzt erstmal diesen direkten Vergleiche mit True oder False umzuschreiben :) die Kommentare habe ich bereits angepasst, werden dann mein "Endprodukt" nochmal dem Forum Vorlegen :D
BlackJack

@Dogy007: Wie schon gesagt, statt ``while flag:`` und dann irgendwann das Flag anders zu setzen, eine ``while True:``-Schleife die an der entsprechenden Stelle einfach durch ein ``break`` oder ``return`` verlassen wird. Wichtiger wäre aber erst einmal das aufteilen in Funktionen die jeweils nur eine Aufgabe lösen statt *alles* in einen grossen Code-Klumpen zu stecken.
BlackJack

Ein möglicher Ansatz das sinnvoll auf Funktionen aufzuteilen:

Code: Alles auswählen

def ask_yes_no(prompt):
    while True:
        answer = input(prompt).lower()
        if answer.startswith('j'):
            return True
        elif answer.startswith('n'):
            return False
        else:
            print('Bitte nur j/J oder n/N eingeben!')


def get_user(users, username):
    for user in users:
        if user['username'] == username:
            return user
    return None


def add_user(users, username, password):
    users.append({'username': username, 'password': password})


def register_user(users):
    while True:
        username = input('Geben sie ihren Benutzernamen ein: ')
        user = get_user(users, username)
        if user is None:
            while True:
                password_a = input('Geben sie bitte ihr Passwort ein: ')
                password_b = input('Bitte bestätigen Sie das Passwort: ')
                if password_a == password_b:
                    add_user(users, username, password_a)
                    print('Registrierung erfolgreich.')
                    return
                else:
                    print('Die Passwörter stimmen nicht überein.')
        else:
            print('Der Benutzername', username, 'ist bereits vergeben.')


def login(users, max_trials=3):
    user = get_user(users, input('Geben sie ihren Benutzernamen ein: '))
    for trials_left in reversed(range(max_trials)):
        password = input('Geben sie bitte ihr Passwort ein: ')
        if user is not None and user['password'] == password:
            break
        if trials_left:
            print('Falsch!  Sie haben noch', trials_left, 'Versuche.')
    else:
        print('Sie haben Ihr Passwort', max_trials, 'mal falsch eingegeben.')
        print()

    return user
    

def register_and_login(users):
    while True:
        if not ask_yes_no('Sind Sie bereits Registriert? Ja/Nein: '):
            register_user(users)

        user = login(users)
        if user is not None:
            return user


def main():
    users = [
        {'username': 'dogy', 'password': 'dogypw'},
        {'username': 'pingu', 'password': 'pingupw'},
    ]
    user = register_and_login(users)
    print('Hallo', user['username'], 'Sie sind angemeldet.')


if __name__ == '__main__':
    main()
Antworten