Seite 1 von 1
Zahlenraten in Konsole
Verfasst: Sonntag 17. März 2013, 13:34
von pyth0ndev
Hallo Leute,
ich wollte mal ein paar erfahrenere Programmierer unter euch fragen, ob es sinnvoll ist, ein seinen Hauptcode innerhalb einer Whileschleife ausführen zu lassen. Meine Frage ergibt sich aus einem aktuellen Script, indem man per Konsole eine Zahl erraten muss. Hier eine verkürzte Version zur Frage:
Code: Alles auswählen
# functions
def weiter():
return True
def stop():
return False
# main
weiterSpiel = weiter()
while weiterSpiel:
# ...sonstiger Code
option = str(input("Tippe ~w~ um weiterzuspielen oder ~b~ zum beenden: "))
if option == "w":
weiterSpiel = weiter()
else option == "b":
weiterSpiel = stop()
Ist diese Methode sinnvoll oder gibt es bessere Varianten?
Re: Programm durch while-Schleife laufen lassen
Verfasst: Sonntag 17. März 2013, 13:46
von webspider
So funktionieren im Grunde genommen Spiele und GUIs. Schöner kann man es aber schon machen. Für eine Endlosschleife reicht ein ``while True:`` aus, mithilfe von ``break`` kann man die Schleife verlassen.
Re: Programm durch while-Schleife laufen lassen
Verfasst: Sonntag 17. März 2013, 14:33
von pyth0ndev
break und continue kenne ich, jedoch kann ich damit nur die Schleife beenden in der ich mich gerade befinde, jedoch habe ich noch eine zweite für ein Optionsmenü eingebaut:
Code: Alles auswählen
import random
# functions
def weiter():
return True
def stop():
return False
# main
print("Errate eine zufällige Nummer zwischen 0 und 100. Viel Glück!\n")
weiterSpiel = weiter()
while weiterSpiel:
geheimeZahl = random.randrange(0,101)
eingabe = 0
i = 0
while eingabe != geheimeZahl:
eingabe = int(input("Raten Sie: "))
if eingabe < geheimeZahl:
print("Zu klein")
elif eingabe > geheimeZahl:
print("Zu gross")
i = i + 1
print(" ")
if i == 1:
print("Super, Sie haben in nur einem Versuch geschafft.")
else:
print("Super, Sie haben es in ", i, "Versuchen geschafft.")
print(" ")
while True:
optionEnde = str(input("Tippe ~w~ um weiterzuspielen oder ~b~ zum beenden: "))
print(" ")
if optionEnde == "w":
weiterSpiel = weiter()
break
elif optionEnde == "b":
weiterSpiel = stop()
break
else:
continue
Die Schleife vom Menü ist damit abgebrochen, aber die Hauptschleife und damit das Programm läuft noch.
Re: Programm durch while-Schleife laufen lassen
Verfasst: Sonntag 17. März 2013, 14:41
von Hyperion
Bitte nutze doch die Python-Code-Tags bzw. das Attribut ``python`` im Code-Tags.
Du solltest das alles besser in Funktionen unterteilen! Was sucht denn das Menü *in* der Hauptschleife des Programms? Dadurch erhältst Du auf Dauer endlos langen Spaghetti-Code, der auf Dauer nicht mehr wartbar bleibt.
Re: Programm durch while-Schleife laufen lassen
Verfasst: Sonntag 17. März 2013, 14:47
von BlackJack
@pyth0ndev: Die Funktionen `weiter()` und `stop()` sind reichlich überflüssig. Stattdessen sollte der Hauptcode besser in einer Funktion verschwinden. Also keinen Kommentar ``# main`` sondern eine Funktion mit dem Namen.
Die innere ``while``-Schleife von der Du sprichst, könnte auch in eine Funktion ausgelagert werden, die dann `True` oder `False` zurück gibt, je nach dem was der Benutzer eingegeben hat. Dann kannst Du damit den Tipp von webspider umsetzen und je nach Ergebnis der Funktion die Hauptschleife mit ``break`` verlassen.
Das manuelle hochzählen von `i` kann man mit `itertools.count()` und einer ``for``-Schleife ersetzen. Dann braucht man `eingabe` auch nicht vor der Schleife an irgendeinen Wert binden, der eigentlich gar nicht verwendet wird. Beziehungsweise ist der im Moment verwendete Wert ungünstig. Überleg mal warum. Diese Schleife dann auch wieder mit einem ``break`` verlassen.
In der letzten Schleife ist der ``else``-Zweig mit dem ``continue`` sinnfrei. Das passiert an der Stelle sowieso. Ebenso sinnfrei ist das Umwandeln vom Rückgabewert von `input()` in eine Zeichenkette, weil das bereits eine Zeichenkette *ist*. Die Zeichenkette mit einem Leerzeichen bei den `print()`-Aufrufen, die nur eine Leerzeile ausgeben sollen ist auch überflüssig. Einfach leer lassen die Klammern.
Dann ist die Einrückung zu weit — Konvention sind vier Leerzeichen pro Ebene und die Namen halten sich nicht alle an den
Style Guide for Python Code.
Statt `randrange()` könnte man `randint()` verwenden und die beiden Grenzen als Konstanten definieren. Dann kann man die sowohl für die Ausgabe der Aufgabe für den Benutzer als auch für das ziehen einer Zahl direkt verwenden und ganz einfach anpassen, ohne dass man die Werte an mindestens zwei Stellen im Programm ändern muss.
Benutzer geben gerne mal etwas falsches ein — darum könnte man sich auch kümmern. Sowohl wenn der Benutzer etwas anderes als eine Zahl eingibt, als auch wenn eine eingegebene Zahl nicht im passenden Bereich ist. Da wären für den Test die Konstanten wieder nützlich.
Re: Programm durch while-Schleife laufen lassen
Verfasst: Sonntag 17. März 2013, 14:56
von pyth0ndev
Danke erstmal für die schnelle und ausführliche Hilfe. Sieht erstmal nach einem großen Berg an Kritik aus, mit dem sich der Code verbessern lässt, aber Übung macht bekanntlich den Meister.
Ich versuche den Code nochmal mit mithilfe Eurer Ideen zur Verbesserung zu überarbeiten. Sollten Schwierigkeiten auftreten, werde ich mich wieder melden
Und Danke nochmals für die großartige Unterstützung.
Re: Programm durch while-Schleife laufen lassen
Verfasst: Sonntag 17. März 2013, 16:43
von pyth0ndev
Ich habe jetzt das Programm in Funktionen unterteilt, jedoch weiß kann ich mit return nicht break bzw. continue zurückzugeben, um die while-Schleife zu beenden
Code: Alles auswählen
# imports
from random import *
import itertools
# functions
def random():
global gesucht
gesucht = randint(0,101)
return gesucht
def count(): # Darf bei Falscheingabe nicht weiter zählen!
counter = itertools.count(1)
for i in counter:
break
print('==================================================')
if i == 1:
print('Es war ein Versuch nötig.')
else:
print(i, ' Versuche Waren nötig.')
def check(zahl):
if zahl == gesucht:
print('Sie wissen die gesuchte Zahl.')
return False
elif zahl < 0 or zahl > 100: # Counter darf nicht weiter zählen!
print(zahl, 'Liegt nicht zwischen 0 und 100.')
elif zahl < gesucht:
print('Die Zahl ist größer.')
return True
elif zahl > gesucht:
print('Die Zahl ist kleiner.')
return True
else:
print('Geben Sie eine Zahl ein!')
# Funktionierende Fehlermeldung fehlt // Schleife geht weiter // Bei return False würde Sie abgebrochen werden
def menu(menuEingabe):
if menuEingabe == 'w':
return True
elif menuEingabe == 'b':
return False
# Funktionierende Fehlermeldung fehlt
def main():
while True:
eingabe = int(input('Geben Sie eine Zahl ein: '))
if check(eingabe) == False:
break
else:
continue
# --- Hauptprogramm --- #
print("Errate eine zufällige Nummer zwischen 0 und 100. Viel Glück!\n")
while True:
random()
main()
count()
print()
menuEingabe = input('Tippe ~w~ um weiterzuspielen oder ~b~ zum beenden: ')
print()
if menu(menuEingabe) == False:
break
elif menu(menuEingabe) == True:
continue
Re: Programm durch while-Schleife laufen lassen
Verfasst: Sonntag 17. März 2013, 17:19
von nomnom
break bzw. continue kann man nicht zurückgeben. Du kannst allerdings für break z.B. True und für continue False zurückgeben, und dann je nachdem in main() entscheiden, wie fortgefahren werden soll.
Re: Zahlenraten in Konsole
Verfasst: Montag 18. März 2013, 16:43
von pyth0ndev
Ich habe jetzt meinen Code soweit es mir möglich war, überarbeitet. Jetzt weiß ich nur noch nicht, wie ich den
Counter richtig einbauen kann. Zudem kann ich die Falscheingaben in durch die Fehlerausgabe nicht beheben. Dabei soll eine Fehler-Meldung ausgegeben werden, jedoch darf der
Counter in diesem Falle nicht weiterzählen.
Habt Ihr sonst noch etwas am Code auszusetzen? Danke für Eure Hilfe im Vorraus
Code: Alles auswählen
# imports
from random import *
import itertools
# functions
def random():
global gesucht
gesucht = 5#randint(0,101)
return gesucht
def count(): # Darf bei Falscheingabe nicht weiter zählen!
counter = itertools.count(1)
for i in counter:
break
print('==================================================')
if i == 1:
print('Es war ein Versuch nötig.')
else:
print(i, ' Versuche Waren nötig.')
def check(zahl):
if zahl == gesucht:
print('Sie wissen die gesuchte Zahl.')
return False
elif zahl < 0 or zahl > 100: # Counter darf nicht weiter zählen!
print(zahl, 'Liegt nicht zwischen 0 und 100.')
elif zahl < gesucht:
print('Die Zahl ist größer.')
return True
elif zahl > gesucht:
print('Die Zahl ist kleiner.')
return True
else:
print('Geben Sie eine Zahl ein!')
# Funktionierende Fehlermeldung fehlt // Schleife geht weiter // Bei return False würde Sie abgebrochen werden
def menu(menuEingabe):
if menuEingabe == 'w':
return True
elif menuEingabe == 'b':
return False
# Funktionierende Fehlermeldung fehlt
def main():
while True:
eingabe = int(input('Geben Sie eine Zahl ein: '))
if check(eingabe) == False:
break
else:
continue
# --- Hauptprogramm --- #
print("Errate eine zufällige Nummer zwischen 0 und 100. Viel Glück!\n")
while True:
random()
main()
count()
print()
menuEingabe = input('Tippe ~w~ um weiterzuspielen oder ~b~ zum beenden: ')
print()
if menu(menuEingabe) == False:
break
elif menu(menuEingabe) == True:
continue
else:
# Programm macht setzt trotz Falscheingabe die Schleife fort
Re: Zahlenraten in Konsole
Verfasst: Montag 18. März 2013, 17:25
von BlackJack
@pyth0ndev: Ich versuche gerade einzelne Verbesserungsvorschläge zu formulieren, mir fällt aber irgendwie nur einer ein: Komplett wegwerfen und neu anfangen. Die Aufteilung auf Funktionen ist *so* nicht sinnvoll. Das funktioniert doch alles hinten und vorne nicht.
Funktionen sollten abgeschlossene Teilaufgaben isoliert lösen. Dabei kann man Argumente übergeben und Rückgabewerte zurück geben. `random()` verletzt das durch ``global`` (das Schlüsselwort bitte ganz schnell vergessen) und der Rückgabewert wird überhaupt nicht verwendet.
`count()` enthält eine Schleife die nur einmal durchlaufen wird, weil alles was drin steht ein ``break`` ist. Da hätte man auch gleich ``i = 1`` schreiben können. In dieser Schleife müssten die Werte erfragt werden und so weiter.
`check()` prüft nicht nur sondern gibt auch Text aus und Ergebnisse zurück und zwar `True`, `False`, oder `None`. Das heisst `None` eigentlich nicht, denn der letzte ``else``-Zweig wird niemals ausgeführt werden, weil alle Möglichkeiten von den ``elif``\s davor schon ausgeschöpft werden. Ausserdem kann beim einzigen Aufruf gar nichts übergeben werden was keine Zahl ist, denn dann hätte die Umwandlung mit `int()` ja schon nicht geklappt. Es werden ausserdem Prüfungen auf gültige Eingaben mit Prüfungen, welche die Spiellogik betreffen vermischt. Daraus resultiert dann auch das Problem mit dem Zähler. Solange der Benutzer keine gültige Eingabe gemacht hat, braucht man mit dem Spiel auch nicht weitermachen (wenn ungültige Eingaben nicht als Versuch zählen sollen).
`menu()` ist als Funktion unsinnig. Ausserdem ist der Name unpassend.
`main()` wäre die Hauptfunktion, also da wo der Hauptprogramm-Code enthalten ist — der steht aber nach dem Kommentar dass es sich um das Hauptprogramm handelt auf Modulebene.
Beide Verwendungen von ``continue`` sind sinnfrei, weil dass an der Stelle sowieso passieren würde.
Explizite Vergleiche mit den `bool`-Literalen `True` und `False` sind schlechter Stil, weil vollkommen überflüssig. Man hat ja sowieso schon einen Wahrheitswert und beim Vergleich kommt nur *wieder* ein Wahrheitswert heraus. Einzig die Negation mit ``not`` macht an der Stelle wirklich sinn, wenn man auf das Gegenteil vom vorhandenen Wahrheitswert testen möchte.