Kalender mit Python erstellen

Code-Stücke können hier veröffentlicht werden.
Antworten
mysterion
User
Beiträge: 8
Registriert: Dienstag 3. Januar 2017, 17:38

Hallo zusammen,

ich soll für die Uni einen Kalender mit python programmieren und bin auch schon fast fertig. Nur leider stehe ich bei der Ausgabe ein bisschen auf dem Schlauch. Der Kalender soll eigentlich so aussehen:

Bild

Bei mir sieht das ganze aber so aus:

Bild

Hier ist mein Code, ich sitze jetzt schon seit vielen Stunden dran und komme einfach nicht auf die richtige Lösung für mein Problem:

Code: Alles auswählen

def leap_year(year):                                       #Definition eines Schaltjahres
    if year % 400 == 0:
        return True
    else:
        if year % 4 == 0:
            if year % 100 == 0:
                return False
            else:
                return True
        else:
            return False


def days_in_month(year, month):                            #Definition der Anzahl der Tage in einem Monat
    if month == 2:
        if leap_year(year) == True:
            return 29
        else:
            return 28   
    elif month in (4, 6, 9, 11):
        return 30
    else:
        return 31
    
def week_day(year, day, month):                            #Definition eines Wochentages
    y = year % 100
    c = year // 100
    if month == 5:
        k = 0
    elif month == 8:
        k = 1
    elif month == 2:
        if leap_year(year) == True:
            k = 1
        else:
            k = 2  
    elif month in (11, 3):
        k = 2
    elif month == 6:
        k = 3
    elif month in (9, 12):
        k = 4
    elif month in (4, 7):
        k = 5
    elif month == 1:
        if leap_year(year) == True:
            k = 5
        else:
            k = 6
    elif month == 10:
        k = 6
    d = (day + k + y + y // 4 - 2 * (c % 4)) % 7
    return d

def month_name(m):                                         #Definition des Monatsnamen
    if m == 1:
        return "Januar"
    if m == 2:
        return "Februar"
    if m == 3:
        return "Maerz"
    if m == 4:
        return "April"
    if m == 5:
        return "Mai"
    if m == 6:
        return "Juni"
    if m == 7:
        return "Juli"
    if m == 8:
        return "August"
    if m == 9:
        return "September"
    if m == 10:
        return "Oktober"
    if m == 11:
        return "November"
    if m == 12:
        return "Dezember"

def calendar(year):                                        #Ausgabe des Kalenders
    W = 0
    for m in range(1, 13):
        s = month_name(m) + ' ' + str(year)
        print('{:^23}'.format(s))
        print('KW', 'SO', 'MO', 'DI', 'MI', 'DO', 'FR', 'SA')
        for day in range(1, days_in_month(year, m)+1):
            t = week_day(year, day, m)*' ' + str(day)           
            print(W, t)
            W += 1
        print()      
            
        
 
calendar(2017)
    
Ich hoffe ihr könnt mir helfen, ist wahrscheinlich auch keine so schwierige Aufgabe, aber ich bin nunmal ein Python-noob :K :D

LG Mysterion
Zuletzt geändert von Anonymous am Dienstag 3. Januar 2017, 18:06, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@mysterion: Schau Dir mal das `calendar`-Modul aus der Standardbibliothek an.
mysterion
User
Beiträge: 8
Registriert: Dienstag 3. Januar 2017, 17:38

@blackjack hab ich mir schon angeguckt, ich habe aber eine bestimmte Aufgabenstellung, die ich verfolgen soll:
Die Ausgabe des Kalenders soll in einer Funktion calendar(year) geschehen, wobei year das
zu druckende Jahr angibt. Ein möglicher Aufruf ist dann calendar(2017), um einen Kalender
für 2017 zu erhalten. Im Folgenden finden Sie einige Tipps für Ihr weiteres Vorgehen. Ich gebe
absichtlich keine Schritt-für-Schritt Anleitung, da die genaue Ausarbeitung der nötigen logischen
Arbeitsschritte ein wesentlicher Teil Ihrer Aufgabe ist!

(a) Initialisieren Sie sich eine Variable für die Kalenderwoche bei 0.

(b) Sie werden zwei ineinander geschachtelte for-Schleifen brauchen, um einerseits die Monate
und andererseits die Tage im Monat durchzugehen. Erinnern Sie sich dazu an das Kommando
range, welches auch mit zwei Argumenten aufgerufen werden kann, z. B. liefert range(1,13)
eine Liste mit den Zahlen 1 bis 12. Für die Anzahl der Tage sollten sie die Funktion
days_in_month(jahr, monat) nutzen.

(c) Nutzen Sie eine Variable line, in welche Sie zunächst den Inhalt einer Zeile schreiben und
nacheinander aufbauen.Wenn die Zeile vollständig ist (wann ist dies der Fall?), geben Sie diese
mit einem print-Befehl aus. Nach jeder ausgegebenenWoche erhöht sich die Kalenderwoche
um 1.


Hinweise:

(1) Die Ausgabe des Kalenders soll schön formatiert sein, wie in den Beispielen
oben. Um dies zu erreichen, benötigen Sie die formatierte Stringausgabe, welche Sie sich in
der Vorbereitung erarbeitet haben. Erkundigen Sie sich auch darüber, wie Sie eine Zeichenkette
innerhalb einer gegebenen Gesamtlänge zentriert ausgeben können (für die Monatsnamen in
der Ausgabe);

(2) Die Funktion week_day ist bei der Erstellung der ersten Woche für jeden
Monat hilfreich.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@mysterion: bei komplizierteren Bedingungen geht man am besten vom häufigsten zum seltensten Fall, so wird beim Lesen auch gleich klar, was die „wichtigste“ Bedingung ist:

Code: Alles auswählen

def leap_year(year):
    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
Durch Listen lassen sich diese langen if-Ketten viel übersichtlicher gestalten:

Code: Alles auswählen

DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
WEEKDAY_OFFSET = [6, 2, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
MONTH_NAMES = ["Januar", "Februar", "Maerz", "April", "Mai", "Juni",
    "Juli", "August", "September", "Oktober", "November", "Dezember",
]
def days_in_month(year, month):
    result = DAYS_IN_MONTH[month - 1]
    if month == 2 and leap_year(year):
        result += 1
    return result

def week_day(year, day, month):
    c, y = divmod(year, 100)
    k = WEEKDAY_OFFSET[month - 1]
    if month <= 2 and leap_year(year):
        k -= 1
    return (day + k + y + y // 4 - 2 * (c % 4)) % 7
 
def month_name(month):
    return MONTH_NAMES[month -1]
Explizit auf »True« zu prüfen ist unnötig.

Laut Aufgabenstellung soll der Wochentag nur für den ersten Tag des Monats bestimmt werden. Die Kalenderwoche fehlt noch ganz.
mysterion
User
Beiträge: 8
Registriert: Dienstag 3. Januar 2017, 17:38

@Sirius3 die Funktionen in meinem Skript sind aus den vorherigen Aufgabenstellungen, dort wurde relativ genau beschrieben wie die einzelnen Funktionen aufgebaut sein sollen. Die Aufgabe die ich gepostet habe ist nur die letzte Aufgabe in der alles zusammengefügt wird.
BlackJack

@mysterion: Schau Dir die von Sirius3 trotzdem mal an, damit Du lernst wie man es machen sollte wenn man keine Vorgaben bekommt es möglichst kompliziert und weniger verständlich zu schreiben. ;-)

Übliches Vorgehen beim Programmieren ist es Probleme in Teilprobleme aufzuteilen. Und diese Teilprobleme wenn es sein muss wieder in Teilprobleme. Solange bis die einzelnen Teilprobleme so klein sind, dass man sie mit je einer Funktion mit wenigen Zeilen Code lösen kann. So eine Teillösung testest Du dann, ob sie auch wirklich das tut was sie soll. Und erst wenn sie funktioniert, gehst Du zur nächsten Teillösung über. Diese Teillösungen verwenden dann irgendwann andere Teillösungen, und ehe Du Dich versiehst, hast Du das Gesamtproblem gelöst.

Dummerweise verhindert die Formulierung der Aufgabenstellung schon eine eigenentwickelte Lösung weil das viel zu genau und zu fest vorschreibt wie der Code auszusehen hat, statt einfach nur das Ergebnis/Ziel zu definieren und gegebenenfalls unverbindlichere Anregungen zur Gestaltung des Codes zu geben. Stattdessen werden Codestruktur und sogar lokale Namen fest vorgegeben. Was ein ziemlich eigenartiges Szenario ist, was beim Programmieren normalerweise nicht vorkommt. Das erste was ich hier bei der Aufteilung in Teilprobleme nämlich im Kopf hätte, wäre die Ausgabe eines Monats. Denn das ist ein Teilproblem das 12 mal nach dem selben Muster passiert, also ein prima Kandidat für eine eigene Funktion wäre.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

mysterion hat geschrieben:die Funktionen in meinem Skript sind aus den vorherigen Aufgabenstellungen, dort wurde relativ genau beschrieben wie die einzelnen Funktionen aufgebaut sein sollen.
Diese Begründung für den weitschweifigen und umständlichen Code kann ich nachvollziehen, würde ihn aber nicht akzeptieren. Schau Dir mal genau Sirius'3 Code an — der ist einfach eleganter und kompakter.
Dein Fehler liegt in im Zusammenbau der Tage einer Woche. Jeder einzelne Tag wird bei Dir zu einer eigenen Kalenderwoche (ab Zeile 87). Du musst über die Tage einer Woche, die Wochen eines Monats sowie die Monate eines Jahres iterieren. Da kommst Du mit zwei Schleifen nicht aus. Und da man bei vielen verschachtelten Schleifen schnell den Überblick verliert, bietet es sich an, die Teilaufgaben wieder in Funktionen zu gliedern.
mysterion
User
Beiträge: 8
Registriert: Dienstag 3. Januar 2017, 17:38

@kbr ich verstehe was du meinst, aber in der Aufgabenstellung steht ja dass ich nur zwei for-schleifen brauche. Ich hab aber keine Ahnung wie ich das ganze mit nur zwei Schleifen hinbekommen soll...
mysterion
User
Beiträge: 8
Registriert: Dienstag 3. Januar 2017, 17:38

Hier ist noch der Rest der Aufgabenstellung, vielleicht hilft euch das dabei mein Problem zu verstehen :wink:

Bild

Bild

Bild
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@mysterion: Na, ja. Mit zwei Schleifen kannst Du auch hinkommen, wenn Du über die Tage eines Monats iterierst. Dann musst Du eben in der Schleife berechnen, wann Du den Zeilenumbruch für die Ausgabe der nächsten Wochenzeile vornimmst. Wenn Du neben dem Tagesdatum die korrespondierenden Wochentage numerisch mitführst, lässt sich dies bequem mit dem Modulo-Operator entscheiden.
BlackJack

Um mal zu illustrieren dass die bisherigen Funktionen des OP kein Python sind; in QBasic sieht das ”richtig” aus was sich in Python so verdammt falsch ”anfühlt” :-)
[codebox=qbasic file=Unbenannt.txt]
FUNCTION LeapYear(year AS INTEGER) AS INTEGER
LeapYear=year MOD 4=0 AND (year MOD 100<>0 OR year MOD 400=0)
END FUNCTION


FUNCTION DaysInMonth(year AS INTEGER, month AS INTEGER) AS INTEGER
SELECT CASE month
CASE 1,3,5,7,8,10,12
DaysInMonth=31
CASE 4,6,9,11
DaysInMonth=30
CASE ELSE
IF LeapYear(year) THEN DaysInMonth=29 ELSE DaysInMonth=28
END SELECT
END FUNCTION


FUNCTION WeekDay(year AS INTEGER, month AS INTEGER, day AS INTEGER)
SELECT CASE month
CASE 1
IF LeapYear(year) THEN k%=5 ELSE k%=6
CASE 2
IF LeapYear(year) THEN k%=1 ELSE k%=2
CASE 3,11
k%=2
CASE 4,7
k%=5
CASE 5
k%=0
CASE 6
k%=3
CASE 8
k%=1
CASE 9,12
k%=4
CASE 10
k%=6
END SELECT
y%=year MOD 100
WeekDay=(day+k%+y%+y%\4-2*(year\100 MOD 4)) MOD 7
END FUNCTION


FUNCTION MonthName$(month as INTEGER)
SELECT CASE month
CASE 1
MonthName="Januar"
CASE 2
MonthName="Februar"
CASE 3
MonthName="Maerz"
CASE 4
MonthName="April"
CASE 5
MonthName="Mai"
CASE 6
MonthName="Juni"
CASE 7
MonthName="Juli"
CASE 8
MonthName="August"
CASE 9
MonthName="September"
CASE 10
MonthName="Oktober"
CASE 11
MonthName="November"
CASE 12
MonthName="Dezember"
END SELECT
END FUNCTION


SUB Calendar(year AS INTEGER)
DIM month AS INTEGER, day AS INTEGER
kw%=0
FOR month=1 TO 12
PRINT MonthName(month);year
PRINT "KW So Mo Di Mi Do Fr Sa"
' ...
FOR day=1 TO DaysInMonth(year,month)
' ...
NEXT
PRINT
PRINT
NEXT
END SUB


Calendar(2016)[/code]
So etwas hätte man in den 80ern wohl noch so geschrieben.
mysterion
User
Beiträge: 8
Registriert: Dienstag 3. Januar 2017, 17:38

@BlackJack kann sein dass mein Programmierstil nicht gerade sehr elegant ist, so haben wir das aber bis jetzt gelernt. Ich habe auch nur im ersten Semester einen sehr elementaren Pythonkurs (ich studiere Physik) und will das ganze einfach hinter mir haben. :D
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@mysterion: mit der Einstellung kommst Du sicher sehr weit. Während man bei Thermodynamik sich ja fragen kann, was brauch ich das später noch, sind Programmierkenntnisse garantiert wichtig. Und je besser Du programmieren lernst, desto einfacher wirst Du es später haben. Dass manche Dozenten das auch nur als lästige Pflicht sehen, ist dann doppelt schade.
Benutzeravatar
pyHoax
User
Beiträge: 84
Registriert: Donnerstag 15. Dezember 2016, 19:17

Dass manche Dozenten das auch nur als lästige Pflicht sehen, ist dann doppelt schade.
Wenn Physiker in ihrem EDV Kurs Kalender programmieren was machen dann Geschichstudenten in Ihren EDV Kursen ?

Ist es so schwer Programmieraufgaben zufinden die mit dem Studium korrelieren ?
BlackJack

Ich will dann auch die furchtbare, zusammengehackte Implementierung der `Calendar`-Funktion in QBasic nicht schuldig bleiben:
[codebox=qbasic file=Unbenannt.txt]SUB Calendar(year AS INTEGER)
DIM month AS INTEGER, day AS INTEGER, firstWeekDay AS INTEGER
kw%=0
FOR month=1 TO 12
m$=MonthName(month)
PRINT SPACE$(11-(LEN(m$)+5)\2);m$;year
PRINT "KW So Mo Di Mi Do Fr Sa"
firstWeekDay=WeekDay(year,month,1)
IF firstWeekDay=0 THEN kw%=kw%+1
PRINT USING "##&";kw%;SPACE$(firstWeekDay*3);
FOR day=1 TO DaysInMonth(year,month)
IF day<>1 AND (firstWeekDay+day-1) MOD 7=0 THEN
kw%=kw%+1
PRINT:PRINT USING "##";kw%;
END IF
PRINT USING "###";day;
NEXT
PRINT:PRINT
NEXT
END SUB[/code]

@pyHoax: Na Geschichtsstudenten berechnen dann Geschwindigkeiten und Ausbreitungen von Gasen bei bestimmten Temperaturen oder Materialermüdung oder ähnliches. ;-)

Bei einem Grundkurs sehe ich jetzt aber erst einmal nichts schlimmes daran allgemeines Programmieren an allgemeinen Beispielprogrammen zu lernen. Wenn es denn vernünftig gemacht ist. Denn auch Wissenstransfer ist ja etwas was man lernen und üben muss als Physiker. Blöd sind halt nur Dozenten die es nicht ernst nehmen, oder in der Entwicklung irgendwo bei QBasic stehen geblieben sind. Was übrigens gar nicht so weit hergeholt ist, denn ich habe selbst mal eine Seminararbeit in der Meteorologie gesehen, wo die gegebene Aufgabe darin bestand eine gegebene einfache Simulation/Vorhersage zu verstehen und zu erklären die als QBasic-Quelltext vorlag. Das ist wohl eine Seminaraufgabe die seit den 90ern immer wieder verwendet wird. Und der Quelltext sah nicht wirklich schön aus. Es gab zwar SUBs und Funktionen, aber das meiste spielte sich in globalen Variablen ab.
Benutzeravatar
pyHoax
User
Beiträge: 84
Registriert: Donnerstag 15. Dezember 2016, 19:17

Bei einem Grundkurs sehe ich jetzt aber erst einmal nichts schlimmes daran allgemeines Programmieren an allgemeinen Beispielprogrammen zu lernen
Mit dem Resutat das beim Thema EDV schon in den Grundkursen Mental abgeschaltet wird. Meine ersten Programme waren nichtsnützige aber fazinierende Simuationen und nicht irgendwelche öden aber nützlichen Tools. Eine Gravitationssimulation über ein Duzent Planeten + Sonne ist nicht schwerer als einen Kalender zu programmieren aber viel spassiger und für einen Physiker eine fachgerechte Aufgabe.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1011
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Ja, hatte auch mal irgendwann durch Zufall das Modul entdeckt.

Code: Alles auswählen

import calendar
cal = calendar.LocaleTextCalendar(locale='de_DE.utf8')
for i in range(1,13):
    print(cal.formatmonth(2017, i))
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten