Eingabe: 08 und 09 funktionieren nicht

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.
bogomip
User
Beiträge: 6
Registriert: Dienstag 28. August 2007, 21:36
Wohnort: Hettenshausen
Kontaktdaten:

Hallo liebe Community!

Mein Name ist Matthias und ich bin neu hier. Aber zum Problem:

Ich möchte (am liebsten im Format dd) einen Tag des Monats einlesen, also logischerweise 01 bis 31. Dafür habe ich folgenden Code:

Code: Alles auswählen

fehler = 1
        while fehler == 1:
            try: 
                parktag = input("Bitte den Tag im Format dd eingeben: ")
                if parktag < 1 or parktag > 31:
                    print "Kein Monat hat einen solchen Tag!"
                    fehler = 1		 		 
                else: 
                    fehler = 0
            except:
                print "Fehlerhafte Eingabe"
Wenn ich das ausführe, kann ich auch alles eingeben. Die führende 0 macht keine Probleme, außer bei 08 und 09. 01 bis 07 kann ich eingeben.
Das finde ich sehr merkwürdig. Das alleinige Eingeben von 8 bzw 9 funktioniert hingegen. Woran kann das liegen?

Danke für Hilfe,

MfG bogomip :)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

bogomip hat geschrieben:input("Bitte den Tag im Format dd eingeben: ")
[...]
Die führende 0 macht keine Probleme, außer bei 08 und 09. 01 bis 07 kann ich eingeben.
Hallo bogomip!

Willkommen im Python-Forum!

Du verwendest ``input()`` statt ``raw_input()``. ``input()`` nimmt "Python-Code" an und versucht diesen zu interpretieren. Python nimmt bei Zahlen, die mit einer 0 beginnen an, dass die Zahl im Oktalsystem vorliegt. Siehe: http://de.wikipedia.org/wiki/Oktales_Zahlensystem
Beim Oktalsystem gibt es keine 8. Deshalb funktioniert dein Code auch nicht.

Verwende stattdessen lieber ``raw_input()``, denn dann bekommst du immer einen String, den du dir dann in das gewünschte Format umwandeln kannst. Z.B. mit ``int()``.

Code: Alles auswählen

retval = raw_input("Bitte den Tag im Format dd eingeben:")
try:
    day = int(retval)
except ValueError:
    print "Gib eine Zahl ein."
if not 1 <= day <= 31:
    print "Gib eine Zahl zwischen 1 und 31 ein"
EDIT:

Na dann erweitern wir die Antwort mal um ein kleines Beispiel mit Modulkopf, rekursivem Funktionsaufruf, Abfangen von STRG+C und einem netten ``if __name__ == "__main__"``: 8) Du musst als Anfänger natürlich nicht sofort alles verstehen. ;-)

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
 
def get_day():
    try:
        retval = raw_input("Tag im Format dd eingeben oder mit STRG+C abbrechen: ")
        try:
            day = int(retval)
            if not 1 <= day <= 31:
                print "Gib eine Zahl zwischen 1 und 31 ein"
                return get_day()
        except ValueError:
            print "Gib eine Zahl ein."
            return get_day()
    except KeyboardInterrupt:
        return None
    return day


def main():
    print "-" * 60
    day = get_day()
    if day is None:
        print "abgebrochen"
    else:
        print "Tag:", day
    print "-" * 60


if __name__ == "__main__":
    main()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

Den rekursiven Funktionsaufruf würde ich nicht machen. Solange es das Rekursionslimit und keine "tail call optimization" gibt, sollte man sich Rekursion für solche Probleme vorbehalten, die auch wirklich von ihrer Struktur her rekursiv sind.

Das `KeyboardInterrupt` in `get_day()` finde ich auch falsch platziert. Es macht die Funktion komplizierter und der Anwender muss beim Rückgabewert immer damit rechnen statt einer Zahl auch ein `None` zu bekommen, also bei *jedem* Aufruf der Funktion auch darauf prüfen, wenn er sauber programmieren will. Angenommen ich will einen Anfangstag und einen Endtag abfragen, dann muss ich entweder mit einer Schleife arbeiten, oder zweimal den Rückgabewert gegen `None` prüfen, statt einfach um beide Aufrufe eine Behandlung für den `KeyboardInterrupt` zu setzen.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo BlackJack!
BlackJack hat geschrieben:Den rekursiven Funktionsaufruf würde ich nicht machen.
Es gibt immer mehrere Möglichkeiten wie man so ein Problem lösen kann. Eines davon ist der rekursive Aufruf der Funktion. Das ist wahrscheinlich nicht besser und nicht schlechter als alles in einer while-Schleife mit Abbruchbedingung zu machen.
BlackJack hat geschrieben:[...]einfach um beide Aufrufe eine Behandlung für den `KeyboardInterrupt` zu setzen.
Spricht nichts dagegen.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
bogomip
User
Beiträge: 6
Registriert: Dienstag 28. August 2007, 21:36
Wohnort: Hettenshausen
Kontaktdaten:

Danke für die freundliche Antwort!

An der erweiterten Lösung werde ich etwas zu beißen haben, aber mit der Zeit wird das auch gehen!

Mein Grundproblem hab ich aber verstanden.

Nen schönen Tag noch :)
BlackJack

@gerold: Bei einer Sprache bzw. Implementierung mit einer Obergrenze für Rekursionsaufrufe und ohne "tail call optimization" ist Rekursion als Ersatz für eine einfache Schleife IMHO die technisch schlechtere Lösung. Das sollte man sich als Lösungsmuster gar nicht erst angewöhnen.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

BlackJack hat geschrieben:@gerold: Bei einer Sprache bzw. Implementierung mit einer Obergrenze für Rekursionsaufrufe und ohne "tail call optimization" ist Rekursion als Ersatz für eine einfache Schleife IMHO die technisch schlechtere Lösung. Das sollte man sich als Lösungsmuster gar nicht erst angewöhnen.
Diese Diskussion wird jetzt ins Lächerliche gezogen. Hier geht es nicht um ein paar 1000 rekursive Aufrufe, sondern nur um ein paar wenige.

Im Moment klingt das so für mich: "Trinke kein Wasser. Gewöhne es dir gar nicht erst an, denn Wasser ist ein knappes Gut."

Oder so: "Verwende kein ``if``, denn wenn du mehrere ``if``s nacheinander verwendest, dann könnte dein Code unübersichtlich werden."

So ganz verstehe ich dich nicht. Ich will dem Fragesteller in einem Beispiel gleich mehrere Techniken und Möglichkeiten aufzeigen (Funktionen, Exceptions, Rekursion,...) und du ziehst das in den Dreck. Schreibe lieber ein Beispiel in dem du aufzeigst, wie du es machen würdest und erkläre warum du das so machst. Dann kann jeder selber wählen was er nehmen möchte.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

gerold hat geschrieben:
BlackJack hat geschrieben:@gerold: Bei einer Sprache bzw. Implementierung mit einer Obergrenze für Rekursionsaufrufe und ohne "tail call optimization" ist Rekursion als Ersatz für eine einfache Schleife IMHO die technisch schlechtere Lösung. Das sollte man sich als Lösungsmuster gar nicht erst angewöhnen.
Diese Diskussion wird jetzt ins Lächerliche gezogen.
Finde ich eigentlich gar nicht. Dies ist eine sehr gute Diskussion in der sich die Standpunkte: "verwende Rekursion wenn möglich" (Gerold) und "verwende Rekursion wenn nötig" (BlackJack) gegenüber stehen. Ich muss sagen, dass ich auch eher zu BlackJacks Ansicht tendieren würde - Python ist kein Scheme und ist eben nicht für Rekursion optimiert. Es hat ein Limit und deine Lösung Gerold funktioniert zwar, ist aber bei genauerer Überlegung kein Code den man vorbehaltslos auf andere Situationen übertragen könnte.
Ich habe Rekursion auch als Lösung für Probleme verwendet, die gar nicht zwangsweise Rekursive Lösungen benötigen, aber dann hatte die Rekursion auch ein niedriges, festgelegtes Limit. Für so Einsatzzwecke ist Pythons Rekursion IMHO optimal.
gerold hat geschrieben:Hier geht es nicht um ein paar 1000 rekursive Aufrufe, sondern nur um ein paar wenige.
In dem Code, ja, vielleicht, aber letztendlich sieht man auf dem Horizont einen Punkt (das Rekursionslimit), das dem ein unausweichliches Ende setzt. Wenn jemand das Programm etwas umarbeitet und für einen anderen Einsatzzweck verwendet, kann er durchaus bis zu diesem Limit kommen.
gerold hat geschrieben:So ganz verstehe ich dich nicht. Ich will dem Fragesteller in einem Beispiel gleich mehrere Techniken und Möglichkeiten aufzeigen (Funktionen, Exceptions, Rekursion,...) und du ziehst das in den Dreck. Schreibe lieber ein Beispiel in dem du aufzeigst, wie du es machen würdest und erkläre warum du das so machst. Dann kann jeder selber wählen was er nehmen möchte.
Ich glaube Gerold, dass du dich unnötig gekränkt fühlst. Es war niemandes Absicht dein Programm in den Dreck zu ziehen, ich als Außenstehender habe BlackJacks Kommentar eben als konstruktive Kritik gesehen.

Aber da ich mich jetzt habe reinziehen lassen, muss ich wohl ein Beispiel zusammenschreiben.. Moment.

Edit: Bitteschön, ich habe Gerolds Code nichtrekursiv gemacht und BlackJacks Anmerkung zu den Exceptions auch mitberücksichtigt:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

def get_day():
    while True:
        retval = raw_input("Tag im Format dd eingeben oder mit STRG+C abbrechen: ")
        try:
            day = int(retval)
            if 1 <= day <= 31:
                return day
            else:
                print "Gib eine Zahl zwischen 1 und 31 ein"
        except ValueError:
            print "Gib eine Zahl ein."

def main():
    print "-" * 60
    try:
        day = get_day()
        print "Tag:", day
    except KeyboardInterrupt:
        print "abgebrochen"
    print "-" * 60


if __name__ == "__main__":
    main()
So Gerold, du darfst mich jetzt auch verreißen 8)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@gerold: Ich wollte Dein Beispiel nicht in den Dreck ziehen! Sorry wenn das so rüberkam.

Es geht nicht um die konkrete Anzahl der rekursiven Aufrufe in diesem Fall, sondern um das Muster im allgemeinen. Man muss wissen, das man dieses Muster nicht allgemein anwenden kann ohne Probleme zu bekommen oder Ressourcen zu verschwenden. Und das sollte man gerade Anfängern deutlich mit auf den Weg geben. Man muss sich zum einen über das Rekursionslimit im klaren sein, das kann man auch erreichen wenn man dieses Muster oft anwendet und sich die verschachtelten Aufrufe von mehreren Funktionen addieren, zum anderen gibt es noch das Problem, dass die Stackframes bei jedem Aufruf die Objekte referenzieren. Das gab's hier auch in Beispielen von Anfängern, die zum Beispiel ein Spiel geschrieben haben und am Ende den Anwender fragen ob er noch eine Runde spielen will und dann einfach die Hauptfunktion erneut aufgerufen haben. Dabei bleiben dann alle Datenstrukturen von allen bisher gespielten Partien im Speicher. Wenn man dann noch eine Pygame-Oberfläche einbaut, die jedesmal neu erstellt wird, kann man mit Grafiken ganz schnell den Hauptspeicher (über)füllen ohne das Rekursionslimit zu erreichen.

Ich sage nicht man sollte nie Wasser trinken, sondern nur dann wenn man auch durstig ist und nicht nur wenn man etwas in den Magen bekommen will. Da gibt's auch Fälle wo man lieber etwas essen sollte. Ausser beim Fasten. Das ist dann die Haskell/Scheme/OCaml-Woche. ;-)

Ein gutes Beispiel für Rekursion wäre ein Problem, das in gleichartige, kleinere Teilprobleme zerlegt wird, welche dann rekursiv gelöst werden.

Den Alternativquelltext hat Leonidas ja schon geschrieben.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Leonidas hat geschrieben:Dies ist eine sehr gute Diskussion in der sich die Standpunkte: "verwende Rekursion wenn möglich" (Gerold) und "verwende Rekursion wenn nötig" (BlackJack) gegenüber stehen.
Hallo Leonidas!

Das sollte eher so heißen: Verwende Rekursion, wenn dir im ersten Moment nichts besseres einfällt und du im Moment keine Lust hast über prinzipielle Alternativen nachzudenken, die dem Programm keine zusätzlichen Vorteile bringen. (Gerold)

Genauso gut könnte man das auch so auslegen: Verwende eine while-Schleife, wenn dir im ersten Moment nichts besseres einfällt und du im Moment keine Lust hast über prinzipielle Alternativen nachzudenken, die dem Programm keine zusätzlichen Vorteile bringen. (Gerold)

Mir geht es nur auf die Nerven, dass BlackJack die letzte Zeit Lösungen als "schlecht" hin stellt, -- ja sogar nieder macht --, nur weil er das anders machen würde. (Zu mindest kommt es mir so vor. -- Und ja, ich bin irgendwie gekränkt.) Anscheinend sind nur seine Lösungen das einzig Wahre. Menschen denken unterschiedlich und kommen trotzdem zu Lösungen. Man kann manches auch anders sagen. Man kann gute Argumente auch vorbringen, ohne dabei andere schlecht zu machen.
Ich bin kein guter Rhetoriker, aber ich bekomme es mit, wenn ich persönlich angegriffen werde. Anscheinend stimmt die Chemie nicht mehr zwischen BlackJack und mir. Ich glaube, wir müssen mal ein paar Whi..., ich meinte Cola, miteinander drinken und alles ausdiskutieren. ;-)

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

BlackJack hat geschrieben:@gerold: Ich wollte Dein Beispiel nicht in den Dreck ziehen! Sorry wenn das so rüberkam.
Hallo BlackJack!

Das ist ein Wort! :D

Der Vorschlag, mal ein Cola ;-) drinken zu gehen, steht noch.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

gerold hat geschrieben:Das sollte eher so heißen: Verwende Rekursion, wenn dir im ersten Moment nichts besseres einfällt und du im Moment keine Lust hast über prinzipielle Alternativen nachzudenken, die dem Programm keine zusätzlichen Vorteile bringen. (Gerold)
Die Vorteile bestehen durchaus - eine while-Schleife kann unendlich oft iterieren, eine Rekursion knallt nach einiger Zeit gegen das Limit. Aber BlackJack hat darauf schon hingewiesen. Ein anderer Vorteil ist, dass die meisten Leute die nicht aus der funktionalen Programmierung kommen eher mit dem Prinzip der Wiederholung als mit dem Prinzip der Rekursion etwas anfangen können. Es gibt auch Bücher darüber, wie "The Little Schemer" die weniger die Sprache lehren und mehr die Rekursion.
gerold hat geschrieben:Mir geht es nur auf die Nerven, dass BlackJack die letzte Zeit Lösungen als "schlecht" hin stellt, -- ja sogar nieder macht --, nur weil er das anders machen würde. (Zu mindest kommt es mir so vor. -- Und ja, ich bin irgendwie gekränkt.) Anscheinend sind nur seine Lösungen das einzig Wahre. Menschen denken unterschiedlich und kommen trotzdem zu Lösungen.
Mir ist nicht aufgefallen, dass BlackJack andere Lösungen nieder macht - er scheibt eben oft seine Kommentare dazu die oftmals dazu führen, dass der Poster sein Programm ändert und verbessert. Dagegen ist nichts einzuwenden. Das seine Lösungen in der Regel besser sind als andere ist meiner Beobachtung nach oft objektiv richtig - auch wenn sie manchmal für Einsteiger übertrieben sind und teilweise auch für Leute die länger dran sind schwer zu überblicken sind. Aber ich finde es gut, Leute zu haben, die einem immer neue Tricks zeigen können - so wird es zumindest mir nicht langweilig.

Es ist ja so, dass ihr beide wertvolle Mitglieder des Forums seid und Probleme auf unterschiedliche Weisen löst. Aber manchmal ist es eben so, dass die Lösung des anderen eben irgendwelche sichtbaren Vorteile hat. Da ist gekränkt sein keine Lösung - dann müsste ich ja hier auf einige böse sein, die meine Quellcodes dumm haben aussehen lassen ;) Anfangs war ich das auch etwas, gebe ich zu, aber seitdem habe ich auch vieles gelernt.

Sollte ich mich nun Ombudsmann nennen? ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

gerold hat geschrieben:Anscheinend stimmt die Chemie nicht mehr zwischen BlackJack und mir. Ich glaube, wir müssen mal ein paar Whi..., ich meinte Cola, miteinander drinken und alles ausdiskutieren. ;-)
Ihr könntet euch ja auf neutralem Boden in München beim nächsten dortigen Usertreffen die Fres^WKöpf^WHand reichen. :D
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Granino
User
Beiträge: 19
Registriert: Freitag 10. August 2007, 15:40

Hallo Gerold,
darf ich als Neuling auch meinen Senf dazu geben?
Meiner Meinung nach sollte man die Rekursion nur dann verwenden, wenn das Programm dadurch leichter zu verstehen ist. Das mag in Deinem Beispiel für Dich persönlich gelten, aber ich kapiere Leonidas' Programm leichter.
Ich ärgere mich immer, wenn ich in Lehrbüchern die Fakultät rekursiv programmiert sehe (ohne Hinweis auf die iterative Lösung). Das ist ineffizient und vor allem für den Anfänger schwer zu verstehen. Dagegen empfinde ich den Sortieralgorithmus 'Quicksort' (von Hoare) einfach genial.
Zum Schluss: Blackjack und Du habt euren Streit inzwischen hoffentlich beigelegt!
Ich empfand Blackjack's Beiträge nicht so provokativ, wie Du es wohl empfunden hast. Mir fielen die Wendungen "würde ich", "sollte man" oder "finde ich" auf, welche ich als neutral oder zurückhaltend empfinde.
BlackJack

Damit die rekursive Fakultät nicht ineffizient ist, schreibt man sie natürlich endrekursiv. ;-)

http://paste.pocoo.org/show/3134/
Granino
User
Beiträge: 19
Registriert: Freitag 10. August 2007, 15:40

Hallo Blackjack,

was ist das denn für eine Programmiersprache (Link)?

Habe ich das mit der Endrekursion richtig verstanden, wenn ich die Fakultät so programmiere

Code: Alles auswählen

    def fak(n) :
        if n == 1 : 
            return(1)
        else :
            return(n*fak(n-1)        # statt return(fak(n-1)*n)
        #
    #
Heißt endrekursiv auch rechtsrekursiv?

Habe aber mal schnell die drei Möglichkeiten programmiert, linear und die beiden rekursiven Arten.
Bei 100 000 Wiederholungen von 100! erhielt ich die Zeiten
t1 = 4,8 Sek; t2 = 9,3 Sek, t3 = 9,2 Sek.
Das heißt, die Art der Rekursion macht bei der Fakultät praktisch nichts aus, was für andere Rekursionen aber nicht gelten muss.

Gruß Granino
Granino
User
Beiträge: 19
Registriert: Freitag 10. August 2007, 15:40

Mir sind eben alle Einrückungen und Leerzeichen verlorengegengen. Wie kann ich das korrigieren?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Granino hat geschrieben:Mir sind eben alle Einrückungen und Leerzeichen verlorengegengen. Wie kann ich das korrigieren?
Den Beitrag editieren und ihn in Code-Tags setzen. Da gibts extra Buttons im Editor dafür.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

@Granino: Scheint Haskell zu sein.
Dein Beispiel ist nicht endrekursiv. Schau Dir zur Erklärung mal das an:
http://de.wikipedia.org/wiki/Endrekursiv
MfG
HWK
BlackJack

Die Sprache die ich da verwendet habe ist Haskell.

Deine Funktion ist nicht Endrekursiv. Endrekursiv ist eine Funktion, wenn der rekursive Aufruf die letzte Aktion in der Berechnung der Funktion ist. Das ist bei Dir in beiden Fällen nicht der Fall, weil das Ergebnis des rekursiven Aufrufs noch mit `n` multipliziert werden muss, bevor das Ergebnis feststeht.

Endrekursion ist deshalb wünschenswert, weil nach dem rekursiven Aufruf keine der lokalen Variablen mehr benutzt werden, was bedeutet, dass man sie schon vorher freigeben kann. Oder wenn sich die Funktion selbst aufruft, kann man den aktuellen Stack-Rahmen einfach wiederverwenden, womit die Rekursion vom Compiler effektiv zu einer einfachen Schleife übersetzt wird. Das zielt nur indirekt auf die Laufgeschwindigkeit sondern mehr auf den unnötigen Speicherverbrauch auf dem Stack in diesem Fall.

Das gilt allerdings nur für Compiler die auch Endrekursion entfernen, oder auf Englisch "tail call optimization" durchführen. Das macht CPython nicht automatisch. Es gibt aber einen lustigen "Hack" als Dekorator, den man auf eine Funktion anwenden kann, von der man sicher weiss, dass sie endrekursiv ist: Tail Call Optimization Decorator. Der "Hack" verändert nicht den Bytecode sondern erkennt den rekursiven Aufruf und löst eine Ausnahme aus bevor die Funktion erneut aufgerufen wird und verhindert so dass der Stack wächst.
Antworten