Funktion Input in While-Schleife verwunderliches Verhalten

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
1xNdR
User
Beiträge: 4
Registriert: Mittwoch 27. August 2008, 15:10
Wohnort: AUT/Tirol/Innsbruck

Hallo erstmal.

Ich bin ein Python-Neuling und habe mal ein bisschen in einem Tutorial gelesen und wollte anschließend soeben erworbenes Wissen durch coden eines Programms testen.

Das Programm funktioniert wiefolgt:

* Es erwartet Zwei mal eine Eingabe und zwar Brutto-Einkommen und Familienstand.

* Der Wert der Funktion input() wird beide male einer Variablen zugewiesen (brutto und fam).

* Nachdem beide Variablen auf bestimmte Kriterien überprüft werden, wird aus ihnen der Steuersatz, das Netto-Einkommen und der Steuerbetrag errechnet/bestimmt und anschließend ausgegeben.


Hier est mal der Code:

Code: Alles auswählen

print "\n\nBitte geben sie ihr Brutto-Gehalt in Euro ein und"
print "bestaetigen Sie die Eingabe mit [Enter]."

#-------------------------Brutto-Einkommen----------------------------#

errorcounter = 1                    # errorcounter = 1 ^=    Error
                                    # errorcounter = 0 ^= No Error

while errorcounter == 1:              
    try:
        brutto = input()
        if brutto>=0:
            errorcounter = 0
        else:
            print "\nIhre Eingabe muss positiv sein."
            print "Bitte ueberpruefen und Eingabe wiederholen."

    except:
        print "\nBitte ueberpruefen Sie ob ihre Eingabe nur aus Zahlen besteht"
        print "und wiederholen sie ihre Eingabe."

#----------------------------Famileinstand-----------------------------#
   
print "\nBitte waehlen sie ihren Familienstand:"
print "     1  = ledig"
print "     2  = verheiratet"

errorcounter2 = 1                 # errorcounter2 = 1 ^=    Error
                                  # errorcounter2 = 0 ^= No Error

while errorcounter2 == 1:
    try:
        fam=input()
        if fam == 1:
            errorcounter2 = 0
        elif fam == 2:
            errorcounter2 = 0
        else:
            print "\nIhre Eingabe muss 1 (Eins) oder 2 (Zwei) sein."
            print "Bitte ueberpruefen und Eingabe wiederholen."
    except:
        print "\nIhre Eingabe muss 1 (Eins) oder 2 (Zwei) sein."
        print "Bitte ueberpruefen und Eingabe wiederholen."


#-------------------------------Berechnungen------------------------------#


if    brutto > 4000 and fam == 1:    #Aufschluesselung des Steuersatzes
    satz = 26
    
elif  brutto > 4000 and fam == 2:
    satz = 22
    
elif brutto <= 4000 and fam == 1:
    satz = 22
    
elif brutto <= 4000 and fam == 2:
    satz = 18

    
def steuer(brutto,fam):
    foo   = (brutto*satz)/100   #Betrag an Steuergeld
    netto = brutto - foo        #Bruttobetrag abzüglich Steuern ^= Nettobetrag

    print "\nIhr Steuersatz betraegt:     ",satz,"%\n"      
    print "Ihr Netto-Einkommen:          %.2f Euro\n"        % (netto)
    print "Der Staat klaute Ihnen:       %.2f Euro\n"        % (foo)

steuer(brutto,fam)
Das Programmm funktioniert soweit recht gut bis auf eine Sache:

Ich habe das Programm laufen lassen und bei der Ersten Eingabe (Brutto-Einkommen) folgendes eingegeben:
"errorcounter == 0"
Dadurch Springt Das Programm weiter zur Familienstand-Abrage (Zeile Nr. 24 in obigem Code).

Nachdem ich mir das Geschehen überlegt habe bin ich zum Schluss gekommen, dass "errorcounter == 0 >= 0"(Zeile 12) als Fehler gewertet wird (Die Eingabe ist nicht vergleichbar mit der Integerzahl brutto).
Folglich springt das Programm sofort in den except-Zweig. Dann will es anschließend wieder mit der while-Schleife von vorne beginnen. Doch gleich in der ersten Zeile der while-Schleife wird diese abgebrochen, da "errorcounter == 1" False ergibt. (In Worten: Die Schleifenbedingung ist nicht erfüllt --> Schleife auslassen, Nachfolgenden Code interpretieren)

Es folgt also nun die Zweite Eingabe. Ich habe mir überlegt ich könnte doch wieder das gleiche wie vorhin probieren. Folgich habe ich "errorcounter2 == 0" eingegeben. Doch das Programm antwortete mit der Meldung aus dem except-Zweig(Zeile 42 und 43) was mich schon mal verwundert hat.

Bei einem weiteren Start des Programmes habe ich an der Stelle der Eingabeaufforderung in der 2. While-Schleife gleich wie in der 1. While Schleife "errorcounter == 0" eingegeben. Beachte: Nicht errorcounter2, sondern wieder errorcounter. Und siehe da, das Programm überspringt die While-Schleife und läuft bis zum Schluss.



* Wieso kommt man mit "errorcounter == 0" durch die 2. While-Schleife?

* Stimmt mein Gedankenweg überhaupt? Habe ich was mit try-except, input oder sonstiges falsch verstanden?

* Kann man durch die Funktion raw_input() erreichen, dass das Programm nicht auf die Eingabe errorcounter == 0 reagiert (also nicht die Schleife überspringt) und falls ja, wie würde so ein Code aussehen? bzw. kann man auch ohne dieser Funktion(raw_input) das Gleiche erreichen?


Danke fürs lesen :) und danke für eine Antwort.

Mfg
1xNdR
Mehr Käse = Weniger Käse (wenn der Käse löcher hat)
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Hallo 1xNdR, willkommen im Forum!

Um auf deine letzte Frage zuerst einzugehen: Ja, du solltest unbedingt raw_input einsetzen und input herauslassen. Dass input() mehr macht, als einfach nur Zahlenwerte entgegenzunehmen, hast du ja schon gemerkt: Es werden nämlich gültge Python-Ausdrücke ausgewertet und das ist meistens nicht das, was man möchte.

Also: raw_input() ist der richtige Weg.

Dabei try/excexpt einzusetzen ist schon vernünftig. Im Fall von raw_input() wird dann eine Zeichenkette geliefert (auch wenn du Zahlenwerte eingibst), die zunächst einmal in Zahlenwerte umgewandelt werden müssen.
1xNdR
User
Beiträge: 4
Registriert: Mittwoch 27. August 2008, 15:10
Wohnort: AUT/Tirol/Innsbruck

Danke für die Antwort.

Ich sehe schon ein dass die Funktion raw_input() (in diesem Fall) einfach "professioneller" oder intellegenter ist, aber zu meiner Frage:
Wieso kommt man mit "errorcounter == 0" durch die 2. While-Schleife?

Lässt sich auf diese Frage vllt. keine vernünftige Antwort geben bzw. ist es ein "nicht nachvollziehbares Verhalten" aufgrund dessen, das die Eingabe bei input() interpretiert wird? Oder ist das nachvollziehbar? Diese Frage interessiert mich rein Neugirde, nicht weil ich versuchen will, die Aufgabenstellung irgendwie doch noch mit input() zu lösen. :wink:
Eher weil ich mir erhoffe, besser zu verstehen, wie Python interpretiert.

Das Problem nochmal auf den Punkt gebracht:

- Es exestiert eine Whileschleife
- Die Bedingung der Whileschleife ist: 'while errorcounter2 == 1'
- Im zuge dieser Whileschleife kommt eine Abfrage mit input()
- Es wird "errorcounter == 0" eingegeben (und nicht errorcounter2 == 0)!

- Wieso wird durch "errorcounter == 0" diese Schleife unterbrochen?

Mfg
1xNdR
Mehr Käse = Weniger Käse (wenn der Käse löcher hat)
BlackJack

Es ist kein Fehler, der beim Vergleich ``brutto >= 0`` auftritt, sondern `brutto` ist in der Tat grösser oder gleich 0. `input()` wertet den eingegebenen Ausdruck im Kontext des Skriptes aus. Da ist `errorcocounter` an eine 1 gebunden und der Vergleich ergibt einen Wahrheitswert. Dieser Wahrheitswert wird dann gegen die 0 getestet und das ergibt `True`:

Code: Alles auswählen

In [3]: errorcounter = 1

In [4]: brutto = input()
errorcounter == 0

In [5]: brutto
Out[5]: False

In [6]: brutto >= 0
Out[6]: True
Mal davon abgesehen, dass man in Python (vor Version 3.0) alle Objekte auf ``>=`` vergleichen kann, ausser die Objekte selbst verhindern das, ist der Typ `bool` eine Unterklasse von `int`, das heisst `True` und `False` verhalten sich bei Rechnungen und Vergleichen wie die Zahlen 1 und 0:

Code: Alles auswählen

In [7]: type(True)
Out[7]: <type 'bool'>

In [8]: issubclass(bool, int)
Out[8]: True

In [9]: True + 2
Out[9]: 3

In [10]: True == 1
Out[10]: True

In [11]: False == 0
Out[11]: True
Das hat historische Gründe, denn früher gab es den Typ `bool` nicht und Vergleiche haben stattdessen 1 und 0 zurück gegeben. Damit alter Quelltext weiterhin funktioniert, müssen sich `True` und `False` entsprechend verhalten.
1xNdR
User
Beiträge: 4
Registriert: Mittwoch 27. August 2008, 15:10
Wohnort: AUT/Tirol/Innsbruck

Vielen Dank für Deine Antwort.

Ich habe sie 4x Druchgelesen, anschliesend ausgiebig darüber nachgedacht, dann einen Zettel genommen und nochmal durchgelesen. Ich denke ich habe es jetz verstanden, bin mir aber nicht sicher, deswegen dieser Post:

Was in der 1. While-Schleife vor sich geht ist:

input:
errorcounter == 0

input wird interpretiert:
errorcounter == 0 ...False, den vorhin wird ja festgelegt, dass errorcounter 1 ist.
anschließend wird überprüft, ob brutto, also errorcounter, also False >= 0 ist.
Ja ist es, denn False ^= 0 und 0 ist >= 0 folglich ergiebt brutto >=0 den Wert True.

2. While-Schleife:
Fall A:
input:
errorcounter == 0
errorcounter == 0 ergiebt True, den errorcounter ist ja tatsächlich 0 (Zeile 13: errorcounter = 0)
Anschließend wird geprüft fam == 1
und ergiebt True, denn True ist schliesslich 1 bzw. True

Jedoch Fall B:

input:
errorcounter2 == 0
errorcounter2 == 0 ergiebt False, denn errorcounter2 ist 1.
Folglich ergeben die Folgenden Zeilen:

"fam == 1"und
"fam == 2"
beide den Wert False, da False 0 ist und nicht 1 oder 2.

Zusammengefasst in 3 Wörtern:

Besser raw_input verwenden!

Jetz sollte halt das was da steht auch richtig sein.
Ist es so richtig?

mfg
1xNdR
Mehr Käse = Weniger Käse (wenn der Käse löcher hat)
1xNdR
User
Beiträge: 4
Registriert: Mittwoch 27. August 2008, 15:10
Wohnort: AUT/Tirol/Innsbruck

Danke für deine Hilfe. Ich glaube ich habe auf meinem PythonWeg einen kleinen Schritt nach vorne gemacht. Falls wiedermal ein Stein im Weg liegt weiss ich jetzt, wo ich nette Leute finde, die mir helfen den Stein wegzuräumen. :wink:
Also <3-lichen Dank nochmal,
mfg
1xNdR
Mehr Käse = Weniger Käse (wenn der Käse löcher hat)
Antworten