Hilfe bei Kalender

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
bertil
User
Beiträge: 8
Registriert: Freitag 15. Januar 2010, 20:15

Moin,
Wir sollen für die Schule ein Programm schreiben, dass den Kalender eines beliebigen Jahres ausgibt. Ohne grafik und son schnickschnack, einfach die Daten und den Wochentag untereinander aufgelistet, unter Berücksichtigung von Schaltjahren und so.
Bei meinem jetzigen Programm bekomme ich den Januar - sogar korekkt, aber dann fliegt er in Zeile 119 mit "unboundlocalerror local variable 'jahr' referenced before assignment" raus. Was ich so zu der Meldung gefunden habe, bringt mich nicht weiter.


Könnt ihr mir helfen?
Danke schonmal!


PS: Wo ich dabei bin: Wie kann ich den Zeichensatz auf UTF-8 stellen um Umlaute zu verwenden?

Code: Alles auswählen

tag = 1
monat = 1
jahr=int(input('jahr eingeben'))


def schaltjahr(jahr):
    jahr=int(jahr)
    if (jahr%400)==0:
        return 1
    elif (jahr%4==0) and (jahr%100)!= 0:
        return 1
    else:
        return 0


#........................ Funktion der Monatslaenge .....................
def monatsl(jahr, monat):
    if monat in [1, 3, 5, 7, 8, 10, 12]:
        return 31
    elif monat in [4, 6, 9, 11]:
        return 30
    elif monat == 2:
        if schaltjahr(jahr) == 1:
            return 29
        else:
            return 28

#........................ Funktion der Jahreslaenge .....................
def jahrl(jahr):
    if schaltjahr(jahr) == 1:
        return 366
    else:
        return 365

#........................ Funktion des Wochentages.....................

# Kennzahlen:

# k=Monatskennzahl
# j=Jahreszahl innerhalb eines Jahrhunderts
# c=Anzahl der vollen vergangenen Jahrhunderte
# d=Tag


def wochentag(jahr, monat, tag):            # Definition wochentag wird angewendet
    if monat in [2,3,11]:                   # falls der Monat Februar, Maerz oder November ist:
        k=2                                 # Monatskennzahl = 2
    elif monat in [1,10]:                   # andernfalls, wenn der Monat Januar oder Oktober ist:
        k=6                                 # Monatskennzahl = 6
    elif monat in [4,7]:                    # andernfalls, wenn der Monat April oder Juli ist:
        k=5                                 # Monatskennzahl = 5
    elif monat==5:                          # andernfalls, wenn der Monat Mai ist:
        k=0                                 # Monatskennzahl = 0
    elif monat==6:                          # andernfalls, wenn der Monat Juni ist:
        k=3                                 # Monatskennzahl = 3
    elif monat==8:                          # andernfalls, wenn der Monat August ist:
        k=1                                 # Monatskennzahl = 1
    elif monat in [9,12]:                   # andernfalls, wenn der Monat September oder Dezember ist:
        k=4                                 # Monatskennzahl = 4
    elif schaltjahr(jahr)==1 and monat==1:  # andernfalls, wenn es ein Schaltjahr und der Monat Januar ist:
        k=5                                 # Monatskennzahl =5
    elif schaltjahr(jahr)==1 and monat==2:  # andernfalls, wenn es ein Schaltjahr und der Monat Februar ist:
        k=1                                 # Monatskennzahl = 1
    else:                                   # bei anderen Varianten:
        k=0                                 # Monatskennzahl = 0



    j=jahr%100


    c=int(jahr/100)

    m=int(j/4)
    d=tag+k+j+m-2*(c%4)

    d=int(d%7)
    if d==0:
        return 'Sonntag'
    elif d==1:
        return 'Montag'
    elif d==2:
        return 'Dienstag'
    elif d==3:
        return 'Mittwoch'
    elif d==4:
        return 'Donnerstag'
    elif d==5:
        return 'Freitag'
    elif d==6:
        return 'Samstag'

#...................... Funktion des naechsten Tages ...........................
def nexttag(tag):
    if monat in [1,3,5,7,8,10] and tag == 31:
        tag = 1

    elif monat in [4,6,9] and tag == 30:
        tag = 1

    elif monat == 2 and schaltjahr(jahr)==0 and tag == 28 or\
         monat == 2 and schaltjahr(jahr) == 1 and tag == 29:
        tag = 1

    elif monat == 12 and tag == 31:
        tag = 1

    else:
        tag = tag + 1
    return tag
#............................... Funktion des naechsten Monats .................
def nextmonat(monat):
    if monat in [1,3,5,7,8,10] and tag == 31:
        monat = monat + 1

    elif monat in [4,6,9] and tag == 30:
        monat = monat + 1

    elif monat == 2 and schaltjahr(jahr)==0 and tag == 28 or\
         monat == 2 and schaltjahr(jahr) == 1 and tag == 29:
        monat = monat + 1

    elif monat == 12 and tag == 31:
        monat = 1
        jahr = jahr + 1

    else:
        monat = monat
    return monat

################################################################################

while tag<32 and monat<13:
    print(str(tag)+'. '+str(monat)+'. - '+str(wochentag(jahr, monat, tag)))
    tag=nexttag(tag)
    monat=nextmonat(monat)
    
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Es gibt das Modul calendar.
bertil
User
Beiträge: 8
Registriert: Freitag 15. Januar 2010, 20:15

Danke, aber eine Fehlerbeschreibung & Verbesserungsvorschläge wären mir lieber, ich will (und muss) das selber fertig machen.
Benutzeravatar
/me
User
Beiträge: 3556
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Du greifst auf eine nicht initialisierte Variable zu.
Benutzeravatar
Masaru
User
Beiträge: 425
Registriert: Mittwoch 4. August 2004, 22:17

Wie wäre es, wenn Du nochmal die Variable "jahr" in die Funktion nextmonat übergibst?
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Welchen Nutzen hat

Code: Alles auswählen

monat = monat
in Zeile 129?
bertil
User
Beiträge: 8
Registriert: Freitag 15. Januar 2010, 20:15

/me hat geschrieben:Du greifst auf eine nicht initialisierte Variable zu.
und was kan ich dagegen tun?
die anderen Tipps bringen mich nicht weiter.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Warum bringt dich der Tipp von Masaru nicht weiter?
bertil
User
Beiträge: 8
Registriert: Freitag 15. Januar 2010, 20:15

Naja, wozu brauche ich da denn das jahr?
Der Schaltjahrestest klappt ja auch so.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

bertil hat geschrieben:
/me hat geschrieben:Du greifst auf eine nicht initialisierte Variable zu.
und was kan ich dagegen tun?
die anderen Tipps bringen mich nicht weiter.
Geht es dir darum, den Code besser zu machen (denn da gibt es einiges) oder geht es nur ums "Hauptsache es läuft und bitte sagt mir, was ich dafür machen muss"?
bertil
User
Beiträge: 8
Registriert: Freitag 15. Januar 2010, 20:15

numerix hat geschrieben:
bertil hat geschrieben:
/me hat geschrieben:Du greifst auf eine nicht initialisierte Variable zu.
und was kan ich dagegen tun?
die anderen Tipps bringen mich nicht weiter.
Geht es dir darum, den Code besser zu machen (denn da gibt es einiges) oder geht es nur ums "Hauptsache es läuft und bitte sagt mir, was ich dafür machen muss"?
Eigentlich hauptsache es läuft, aber ich halte mich acuh dazu fähig, Tipps zur Übersichtlichkeit umzusetzen.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

bertil hat geschrieben:Naja, wozu brauche ich da denn das jahr?
Der Schaltjahrestest klappt ja auch so.
Ich glaube, du verstehst die Fehlermeldung gar nicht.
Erstens: In Zeile 119 (wie von dir genannt) kann gar kein Fehler kommen, weil die Zeile leer ist.
In Zeile 120 wird auf einen Bezeichner "jahr" zugegrifffen, der aber weder global noch lokal in der Funktion existiert -> Fehler!
i1337
User
Beiträge: 11
Registriert: Mittwoch 23. September 2009, 15:39

Dein Fehlercode:
File "<module1>", line 120, in nextmonat
UnboundLocalError: local variable 'jahr' referenced before assignment

soll heißen:
du greiffs auf die variable 'jahr' zu, bevor diese Erstellt wurde

'jahr' ist zwar global vorhanden, aber nicht local in der Funktion 'nextmonat'.

Übergib 'jahr' einfach beim Aufruf von 'nextmonat'.

Code: Alles auswählen

Zeile 137: monat=nextmonat(monat, jahr)
Den Kopf von 'nextmonat' musst du auch noch anpassen:

Code: Alles auswählen

Zeile 113: def nextmonat(monat, jahr):
bertil
User
Beiträge: 8
Registriert: Freitag 15. Januar 2010, 20:15

Ok, danke schonmal.
Ich rätsel weiter, warum ich nur den Januar rausbekomme, werde ich aber denke ich auch alleine schaffen.
Wie war das jetzt mir den Verbesserungsvorschlägen, numerix?
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Auch wenn ich nicht numerix heiße... (betrifft die Zeilen 79-92)

Code: Alles auswählen

>>> wochentage = [
...     'Sonntag',
...     'Montag',
...     'Dienstag',
...     'Mittwoch',
...     'Donnerstag',
...     'Freitag',
...     'Samstag'
... ]
>>> # d kann z.B 3 sein
>>> d = 3
>>> wochentag = wochentage[d]
>>> print wochentag
Mittwoch
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Willkommen im Forum!

Warum stehen in den ersten 5 Zeilen Zuweisungen, die du aber erst am Ende des Skripts brauchsts?

Der Name schaltjahr ist schlecht gewählt. Erzeugt es ein Schaltjahr? Nein, es überprüft, also wäre `is_schaltjahr` besser. Zeile 8 ist überflüssig. Sorg lieber vorher dafür, dass du eine Zahl übergeben bekommst. Statt 1 und 0 verwende lieber True und False und lass die Klammern weg:

Code: Alles auswählen

def is_schaltjahr(jahr):
    if not jahr%400 or not jahr%4 and jahr%100:
        return True
    else:
        return False
monatsl ist ebenso ein schlechter Name. Besser sowas wie len_of_month. Gleiches gilt bei jahrl.
Zeile 61 wird nie angewendet werden, da der if-Block davor schon fündig geworden ist.


Warum einmal mit und einmal ohne `int`? Ah, ich habs verstanden. Um den Rest wegzubekommen mach lieber 2 `/` Verwende lieber divmod:

Code: Alles auswählen

    j=jahr%100
    c=int(jahr/100) #c=jahr//100

    c,j = divmod(jahr,100)
Du hast zuviele Kommentare da wo es nicht unbedingt notwendig ist und keine, wo eher welche Sinn machen (Z. 76). Warum erläuterst du nicht das Prinzip, dass du verwendest, oder einfach den Namen des Algorythmus?
Zeilen 79-92 lässt sich verkürzen.

Code: Alles auswählen

return ('Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag')[d]
Warum gibts du eigentlich keine Zahl zurück? Das macht hier mehr Sinn. Dann kannst du später immernoch leicht den Wochentag in einen String umwandeln.

Sich wiederholende Sachen wie `[1,3,5,7,8,10]` lassen sich besser an eine Variable binden. Das ist übersichtlicher. Zeilen 120 und 121 lassen sich verkürzen:

Code: Alles auswählen

monat==2 and (tag == 28+is_schaltjahr(jahr)
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

jbs hat geschrieben:

Code: Alles auswählen

monat==2 and (tag == 28+is_schaltjahr(jahr)
Das "28+" hätte ich zwar ebenso gelöst, aber es passt eigentlich nicht so recht zu deinem Vorschlag, die Funktion is_schaltjahr() einen Wahrheitswert zurückliefern zu lassen (ja, sicher funktioniert das auch so, aber es ist für Anfänger nicht offensichtlich, dass "28+True = 29" ist).

Und: Man sollte sich entscheiden, ob man durchgäng englische oder deutsche Bezeichner wählt: is_leapyear() oder ist_schaltjahr()

Edit: Alternativ:

Code: Alles auswählen

def ist_schaltjahr(jahr): 
    return bool(not jahr%400 or not jahr%4 and jahr%100)


Könnte man jetzt auch mit lambda machen ...
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Bloß nicht! Lambda ist immer unleserlich! IMMER! :twisted:
Antworten