Python Anfänger

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
AnAngel
User
Beiträge: 3
Registriert: Dienstag 26. April 2016, 09:39
Wohnort: Sonneberg

Hallo,

ich bin Anfänger in Sachen Python und wollte mal eure Meinungen und Verbesserungsvorschläge für folgendes einfaches Script:

Code: Alles auswählen

from random import randint

print("10 Richtige Aufgaben lösen")


rechenz = "+"
richtige = 0


while richtige < 10:
    z1 = randint(1,100)
    z2 = randint(1,10)
    sollantwort = z1+z2
    try:
        eingabe = int(input('Was ergibt {0}{1}{2}? '.format(z1, rechenz, z2)))
        if eingabe == sollantwort:
             richtige = richtige + 1
             print("Richtig", richtige, "von 10")
             print()
        else:
             print("Falsch!!!")

    except ValueError:
        print("Bitte eine Zahl eingeben!!!")

eingabe = input("Bitte eine Zahl eingeben!!!")
Chris
BlackJack

@AnAngel: Der ``try``-Block sollte möglichst wenig Code umfassen. Von dem ``except``-Block wird ja nur die erste Zeile vom ``try``-Block korrekt behandelt. Sollte der Benutzer eine Zahl eingeben und in einer der restlichen Zeilen des ``try``-Blocks würde ein `ValueError` ausgelöst, dann wäre der Benutzer sicherlich sehr verwirrt das er aufgefordert wird eine Zahl einzugeben, denn das hat er ja getan. Für die Änderung des Quelltextes ist es nützlich das ``try``/``except`` auch einen ``else``-Block haben kann.

Die letzte Programmzeile macht keinen Sinn‽
Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Die Eingabe eines Zahlenwertes sollte man in eine eigene Funktion auslagern.
AnAngel
User
Beiträge: 3
Registriert: Dienstag 26. April 2016, 09:39
Wohnort: Sonneberg

BlackJack hat geschrieben:@AnAngel: Der ``try``-Block sollte möglichst wenig Code umfassen. Von dem ``except``-Block wird ja nur die erste Zeile vom ``try``-Block korrekt behandelt. Sollte der Benutzer eine Zahl eingeben und in einer der restlichen Zeilen des ``try``-Blocks würde ein `ValueError` ausgelöst, dann wäre der Benutzer sicherlich sehr verwirrt das er aufgefordert wird eine Zahl einzugeben, denn das hat er ja getan. Für die Änderung des Quelltextes ist es nützlich das ``try``/``except`` auch einen ``else``-Block haben kann.

Die letzte Programmzeile macht keinen Sinn‽
Etwa so:

Code: Alles auswählen

from random import randint

print("10 Richtige Aufgaben lösen")


rechenz = "+"
richtige = 0


while richtige < 10:
    z1 = randint(1,100)
    z2 = randint(1,10)
    sollantwort = z1+z2
    try:
        eingabe = int(input("Was ergibt {0}{1}{2}? ".format(z1, rechenz, z2)))
    except ValueError:
        print("Bitte eine Zahl eingeben!!!")
    else:
        if eingabe == sollantwort:
            richtige = richtige + 1
            print("Richtig", richtige, "von 10")
            print()
        else:
            print("Falsch!!!")
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@AnAngel: Variablennamen sollten möglichst sprechend sein. Bei rechenz bleibt die Frage, was denn das z bedeuten soll. Zahl, Zustand, Zusammenfassung? Genauso bei richtige oder z1, z2. Was ist da richtig?
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Der Vollständigkeit halber dann noch der Hinweis, dass es wohl

print("10 Aufgaben richtig lösen")

heißen sollte :)
BlackJack

@AnAngel: Noch zwei Anmerkungen:

Zahlwerte die mehrfach im Quelltext vorkommen, aber die gleiche Bedeutung haben, sollte man als Konstante definieren. Dann kann man den Wert an *einer* Stelle im Quelltext ändern und muss nicht alle Vorkommen suchen und anpassen, wenn man beispielsweise die Anzahl der erwarteten richtigen Lösungen ändern möchte.

Dass das Rechenzeichen nicht fest in der Zeichenkette steht sondern an einen Namen gebunden und in die Zeichenkette mit der Aufgabe hineinformatiert wird, macht hier (noch) keinen Sinn. Die Addition steht ja auch hart im Quelltext. Um das variabel zu gestalten, müsste man auch die Durchführung der Rechenoperation dynamischer machen. Das `operator`-Modul hat für alle Operatoren die Python kennt, jeweils eine Funktion. Zum Beispiel `add()` für den ``+``-Operator.
AnAngel
User
Beiträge: 3
Registriert: Dienstag 26. April 2016, 09:39
Wohnort: Sonneberg

BlackJack hat geschrieben:@AnAngel: Noch zwei Anmerkungen:

Zahlwerte die mehrfach im Quelltext vorkommen, aber die gleiche Bedeutung haben, sollte man als Konstante definieren. Dann kann man den Wert an *einer* Stelle im Quelltext ändern und muss nicht alle Vorkommen suchen und anpassen, wenn man beispielsweise die Anzahl der erwarteten richtigen Lösungen ändern möchte.

Dass das Rechenzeichen nicht fest in der Zeichenkette steht sondern an einen Namen gebunden und in die Zeichenkette mit der Aufgabe hineinformatiert wird, macht hier (noch) keinen Sinn. Die Addition steht ja auch hart im Quelltext. Um das variabel zu gestalten, müsste man auch die Durchführung der Rechenoperation dynamischer machen. Das `operator`-Modul hat für alle Operatoren die Python kennt, jeweils eine Funktion. Zum Beispiel `add()` für den ``+``-Operator.
Habe das Script nochmals überarbeitet. Was haltet Ihr davon?

Code: Alles auswählen

from random import randint
import operator

anzahl_aufgaben = 10
zaehler = 0

print(anzahl_aufgaben, "Aufgaben richtig lösen")

def zufallszahl(start,stop,start2,stop2):
    global zahl1, zahl2
    zahl1 = randint(start,stop)
    zahl2 = randint(start2,stop2)
def eingabe():
    global istantwort
    try:
        istantwort = int(input("Wieviel ist {0}{1}{2} ".format(zahl1,rechenoperation,zahl2)))
    except ValueError:
            print("Bitte eine Zahl eingeben!!!")
def plus():
    global sollantwort, rechenoperation
    rechenoperation = "+"
    zufallszahl(1,100,1,100)
    eingabe()
    sollantwort = operator.add(zahl1,zahl2)
    istantwort

def minus():
    global sollantwort, rechenoperation
    rechenoperation = "-"
    zufallszahl(1,100,1,100)
    eingabe()
    sollantwort = operator.sub(zahl1,zahl2)
    istantwort

def mal():
    global sollantwort, rechenoperation
    rechenoperation = "*"
    zufallszahl(1,10,1,10)
    eingabe()
    sollantwort = operator.mul(zahl1,zahl2)
    istantwort

while zaehler < anzahl_aufgaben:
# Rechenart hier wählen!!!
    plus()
# Rechenart hier wählen!!!    
    if istantwort == sollantwort:
        zaehler = zaehler + 1
        print("Richtig!", zaehler, "von", anzahl_aufgaben)
    else:
        print("Leider falsch!")
BlackJack

@AnAngel: Gar nicht gut: Vergiss am besten sofort das es ``global`` überhaupt gibt. Der Sinn von Funktionen ist das man Code in einzeln verwendbare und testbare Einheiten kapselt, also so eine Art Blackbox wo man Werte rein steckt, die Funktion etwas damit macht, und dann ein Ergebnis liefert. Werte, ausser Konstanten, sollten Funktionen (und Methoden) deshalb als Argumente betreten und als Rückgabewerte verlassen, und nicht ”magisch” irgendwo aus der Umgebung genommen werden, und schon gar nicht dort auch noch verändert werden. Da verliert man ganz schnell den Überblick welche Werte von welchem Code geändert werden.

Wenn Du mit Funktionen arbeitest sollte deshalb auch das Hauptprogramm in einer Funktion stehen und auf Modulebene nur noch Konstanten, Funktionen, und Klassen definiert werden. Dann kommt man gar nicht erst in die Situation ``global`` verwenden zu müssen.

Die `eingabe()`-Funktion ist fehlerhaft weil die im Fall das der Benutzer keine Zahl eingibt, das zwar sagt, aber der Code dann weiterläuft als wäre nichts geschehen, was dann in der Folge entweder zu einer Ausnahme führen wird, oder dazu dass das Programm mit einem falschen Wert arbeitet.

Die Funktionen zu den Rechenoperationen sehen alle fast gleich aus. Solche Code-Wiederholungen will man durch den Einsatz von Funktionen doch gerade vermeiden, in dem man den gemeinsamen Teil nur einmal schreibt und die Unterschiede als Argumente übergibt. Dann braucht man bei Veränderungen und Fehlerbehebungen an der Rechnung nur *eine* Funktion anpassen und nicht drei fast gleiche Funktionen, wobei man dann immer darauf achten muss auch alle gleichwertig zu ändern, damit keine Unterschiede auftreten oder sich gar Fehler einschleichen.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@AnAngel: Du benutzt keine Funktionen sondern nur benannte Code-Abschnitte, wo jeder von jedem über globale Variablen abhängt. Hier mal Dein Code so umgeschrieben, dass er Funktionen verwendet:

Code: Alles auswählen

from random import randint
import operator

ANZAHL_AUFGABEN = 10

def zufallszahlen(start1, stop1, start2, stop2):
    zahl1 = randint(start1, stop1)
    zahl2 = randint(start2, stop2)
    return zahl1, zahl2

def eingabe(zahl1, zahl2, rechenoperation):
    while True:
        try:
            return int(input("Wieviel ist {0}{1}{2} ".format(zahl1, rechenoperation, zahl2)))
        except ValueError:
                print("Bitte eine Zahl eingeben!!!")

def rechne(operation, rechenoperation, max_number):
    zahl1, zahl2 = zufallszahlen(1, max_number, 1, max_number)
    istantwort = eingabe(zahl1, zahl2, rechenoperation)
    sollantwort = operation(zahl1,zahl2)
    return sollantwort == istantwort

def plus():
    return rechne(operator.add, '+', 100)

def minus():
    return rechne(operator.sub, '-', 100)

def mal():
    return rechne(operator.mul, '*', 10)

def main():
    print(ANZAHL_AUFGABEN, "Aufgaben richtig lösen")
    zaehler = 0
    while zaehler < ANZAHL_AUFGABEN:
        # TODO: Rechenart hier wählen!!!
        ergebnis = plus()
        if ergebnis:
            zaehler += 1
            print("Richtig!", zaehler, "von", ANZAHL_AUFGABEN)
        else:
            print("Leider falsch!")
            
if __name__ == '__main__':
    main()
Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

AnAngel hat geschrieben:Habe das Script nochmals überarbeitet. Was haltet Ihr davon?
Abstand.
Antworten