Seite 1 von 1

Continue, Break

Verfasst: Donnerstag 9. April 2020, 12:45
von anniika_s00
Hallo,
Ich bin noch relativ neu in dem ganzen Thema und habe sofort schon ein Problem:
Als Aufgabe soll ein Programm geschrieben werden, welches die Fakultät einer ganzen, positiven Zahl ausgibt. Außerdem soll bei einer ungültigen Eingabe darauf hingewiesen werden und eine neue Eingabe aufgerufen werden. Bei Eingabe der 0 soll das Programm beendet werde. Als Hinweise wurde gesagt, man soll mit continue und break arbeiten. Ich habe das Programm geschrieben, allerdings funktioniert genau das bei mir irgendwie nicht und ich finde keinen Fehler. Als Fehlermeldung wird mir entweder "Break outside loop" oder "Continue not properly in loop" angezeigt.
Vielleicht kann mir jemand helfen...
Hier mein Programm:
a= float(input("Bitte eine ganze positive Zahl: "))
b=0
erg=1

if a<0: #positive Zahl?
print("Die Zahl muss positiv sein!")
a= input("Bitte eine neue Zahl: ")
continue
elif a==0: #Option, das Spiel bei Eingabe von 0 zu beenden
print("Das Spiel ist zu Ende!")
break

elif ((a-int(a))==0) is False: #ganze Zahl?
print("Die Zahl muss eine ganze Zahl sein!")
a= input("Bitte eine neue Zahl: ")
continue

else: #alle Vorgaben erfüllt?
while b<a:
erg=erg*(b+1)
b+=1
print("Das Ergebnis von ", int(a), "!", "ist ", erg, ".")

Schonmal vielen Dank für die Hilfe :D

Re: Continue, Break

Verfasst: Donnerstag 9. April 2020, 13:40
von Jankie
Bitte beim Posten von Code den Codeblock wählen (im vollständigen Editor auf </>), sonst geht die Einrückung verloren. Du hast das break und continue ja nicht innerhalb einer Schleife. Hier kannst du mehr darüber lesen:
https://py-tutorial-de.readthedocs.io/d ... -schleifen. Du bist auch ziemlich unkonsequent beim umwandeln von inputs.
elif ((a-int(a))==0) das funktioniert so auch nicht, da du vorher a als einen String einliest (input liefert immer einen String) und du kannst kein Integer von einem String abziehen.

Ich würde das so lösen:

Eine Funktion die die Berechnung der Fakultät übernimmt. Wird eine negative Zahl als Parameter übergeben wird ein ValueError erzeugt (mit raise), wenn der Paramter eine 0 ist, wird eine 1 zurückgegeben und wenn die Zahl eine positive Ganzzahl ist wird die Fakultät berechnet. Das ganze kann man dann in ein try/except und in eine while True Schleife packen.

Code: Alles auswählen

def berechne_fakultaet(number):
    if number < 0:
        raise ValueError
    if number == 0:
        return 1
    else:
        fakultaet = 1
        for i in range(2, number + 1):
            fakultaet *= i
        return fakultaet

while True:
    try:
        number = int(input("Bitte Ganzzahl eingeben: "))
        print(f" Fakultät von {number} ist {berechne_fakultaet(number)}")
    except ValueError:
        print("Ungültige Eingabe!")


Code zum berechnen der Fakültät habe ich hier aus dem Forum und nur variablen umbenannt. (viewtopic.php?t=12585) Im math Modul gibts auch math.factorial() was du auch benutzen könntest.

Re: Continue, Break

Verfasst: Donnerstag 9. April 2020, 14:24
von __blackjack__
@Jankie: `a` ist eine Gleitkommazahl, also funktioniert ``a - int(a) == 0`` und ist ein etwas umständlicher Weg um ``a.is_integer()`` zu schreiben.

Re: Continue, Break

Verfasst: Donnerstag 9. April 2020, 15:06
von __blackjack__
@anniika_s00: Beide Fehlermeldungen weisen ja recht deutlich darauf hin, dass sich ``break`` und ``continue`` in einer Schleife befinden müssen. Denn die beiden Anweisungen beziehen sich ja darauf eine Schleife abzubrechen oder sofort den nächsten Schleifendurchlauf zu beginnen.

Was da also fehlt ist die ”Endlosschleife”, die den ganzen Code den Du geschrieben hast, enthält. Und dann haben die beiden ``continue``-Anweisungen keinen Effekt. Die kann man weg lassen, ohne das sich am Programmablauf etwas ändert. Das ist auch gut so, denn ``continue`` sollte man vermeiden und kann man in der Regel auch leicht vermeiden.

`a`, `b`, und `erg` sind keine guten Namen. Man kürzt Namen nicht kryptisch ab, die sollen doch dem Leser vermitteln was der Wert dahinter bedeutet. Wenn man `ergebnis` meint, sollte man das auch schreiben. Ausserdem sollte man Namen erst definieren wenn man sie braucht. Zwischen der Initialisierung von `b` und `erg` und dem Code der dann tatsächlich etwas damit macht, liegen nicht nur viele Zeilen Code, sondern es ist auch überhaupt noch nicht klar ob die beiden Variablen überhaupt benutzt werden.

Wenn der Benutzer eine ganze Zahl eingeben muss, warum wandelst Du die Eingabe dann mit `float()` in einen Dezimalbruch um? Und nicht gleich mit `int()` in eine ganze Zahl? Denn auch bei `float()` muss man den `ValueError` behandeln der entsteht wenn der Benutzer etwas eingibt das nicht in eine Gleitkommazahl umgewandelt werden kann.

Dann brauchst Du auch diesen komplizierten Ausdruck nicht: ``(a - int(a)) == 0) is False``. Da ist als erstes mal das ``is False`` falsch. Das macht man nicht. Der Ausdruck dafür ist ja bereits ein Wahrheitswert und bei dem ``is``-Vergleich kommt nur wieder ein Wahrheitswert heraus. Und zwar das Gegenteil von dem Wahrheitswert des Ausdrucks vor dem ``is``. Das kann man aber mit ``not`` bekommen: ``not a - int(a) == 0``. Das ``not`` kann man sich sparen in dem man die Vergleichsbedingung umdreht: ``a - int(a) == 0``. Aber wie ich in der Antwort an Jankie schon schrieb: `a.is_integer()`. Da braucht man dann auch keinen Kommentar mehr der Erklärt warum der Code das macht was der da macht. Ist aber alles sowieso nicht nötig wenn man die Eingabe gleich in eine ganze Zahl wandelt, denn dann braucht man nicht mehr darauf testen.

Das Du da mehrfach im Code das einlesen von `a` stehen hast ist auch falsch. Erstens wandelst Du die Zeichenkette da gar nicht in eine Zahl um, und zweitens kann der Benutzer dabei doch auch wieder Fehler machen oder eine 0 eingeben.

Den Fall mit dem Abbruch des Programms würde ich nach der Eingabe als erstes behandeln. Das sollte so geschrieben sein, dass man möglichst deutlich erkennt was da passiert.

Bei der Fakultät sollte man die laufende Zahl von 1 bis `zahl` laufen lassen, nihct von 0 bis `zahl - 1` und dann bei der Rechnung immer unnötigerweise +1 rechnen müssen. Also statt:

Code: Alles auswählen

                i = 0
                ergebnis = 1
                while i < zahl:
                    ergebnis *= i + 1
                    i += 1
besser:

Code: Alles auswählen

                i = ergebnis = 1
                while i <= zahl:
                    ergebnis *= i
                    i += 1
Wobei das ganz klar ein Fall für eine ``for``-Schleife ist:

Code: Alles auswählen

                ergebnis = 1
                for i in range(1, zahl + 1):
                    ergebnis *= i + 1
Beziehungsweise für `functools.reduce()`:

Code: Alles auswählen

from functools import reduce
from operator import mul
...
                ergebnis = reduce(mul, range(1, zahl + 1), 1)
Oder halt gleich `math.factorial()`.

Wenn man `print()` so verwendet wie Du das verwendest, dann ist zwischen der Zahl und dem "!" ein Leerzeichen, und auch vor dem Satzende. Man formatiert die Werte am besten in *eine* Zeichenkette und gibt die dann aus.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
from math import factorial


def main():
    while True:
        try:
            zahl = int(input("Bitte eine ganze positive Zahl: "))
        except ValueError:
            print("Die Zahl muss eine ganze Zahl sein!")
        else:
            if zahl == 0:
                print("Das Spiel ist zu Ende!")
                break

            try:
                ergebnis = factorial(zahl)
            except ValueError:
                print("Die Zahl muss positiv sein!")
            else:
                print(f"Das Ergebnis von {zahl}! ist {ergebnis}.")


if __name__ == "__main__":
    main()

Re: Continue, Break

Verfasst: Donnerstag 9. April 2020, 20:38
von __blackjack__
Upsi, die Variante mit der ``for``-Schleife hat ein ``+ 1`` zu viel und muss natürlich wie folgt lauten:

Code: Alles auswählen

                ergebnis = 1
                for i in range(1, zahl + 1):
                    ergebnis *= i