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 .
Hier der Code:
https://repl.it/DiM4/0
Vielen Dank schonmal für Eure Hilfe
Neuling sucht Hilfe bei Fehlersuche
@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.
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.
@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.
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.
@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.
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.
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
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
@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.
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()