Schaltjahr bestimmen

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.
Max804
User
Beiträge: 8
Registriert: Montag 28. November 2022, 18:43

Hallo,
ich weiß, dass es bereits hier Lösungen zu dem Problem gibt, jedoch hänge ich fest und weiß nicht mehr weiter.
Wir sollen eine Methode schreiben, welche bei einer ganzzahligen Eingabe bestimmt ob das Jahr ein Schaltjahr ist. Der Bereich kann zwischen 1 und 9999 liegen. Die Rückgabe der Methode soll True sein wenn es ein Schaltjahr ist, und ansonsten False.
Vorgehensweise:
1. Wenn das Jahr ohne Rest durch 4 teilbar ist, gehe zu Schritt 2. Ansonsten gehe zu Schritt 5.
2. Wenn das Jahr ohne Rest durch 100 teilbar ist, gehe zu Schritt 3. Ansonsten gehe zu Schritt 4.
3. Wenn das Jahr ohne Rest durch 400 teilbar ist, gehe zu Schritt 4. Ansonsten gehe zu Schritt 5.
4. Das Jahr ist ein Schaltjahr (366 Tage).
5. Das Jahr ist kein Schaltjahr (365 Tage).

Den Rückgabewert sollen wir mit Hilfe von return zurückgeben.

Code: Alles auswählen

def Schaltjahr(jahr):
    if (jahr % 4 == 0) and (jahr % 100 != 0) or (jahr % 400 == 0):
        jahr = True
    else: 
        jahr = False
Kontrolliert wird so:

Code: Alles auswählen

assert Schaltjahr(2020)
assert not Schaltjahr(2021)
Mein Problem ist, dass ich jedes mal einen AssertionError kriege. Ich bin noch neu in Informatik, deswegen weiß ich die Bedeutung davon auch nicht. Ich hoffe man kann mir helfen.

LG
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Max804: Lass Dir doch mal den Rückgabewert ausgeben.

Und wie kann ein `jahr` Wahr oder Unwahr sein? `jahr` sollte immer eine Zahl sein und nicht an `True` oder `False` gebunden werden.

Zudem ist das Ergebnis der ``if``-Bedinung ja bereits ein Wahrheitswert. Also brauch mal kein ``if`` sondern das Ergebnis ist schon das Ergebnis der Bedingung.

Die Klammern dort sind übrigens überflüssig und sollten Weg.

Und man sollte auch alle möglichen Varianten prüfen, nicht nur ein Schaltjahr und ein Nicht-Schaltjahr, auch die Fälle wo es wichtig ist, ob es durch 100/400 teilbar ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Max804
User
Beiträge: 8
Registriert: Montag 28. November 2022, 18:43

__blackjack__ hat geschrieben: Montag 28. November 2022, 19:33 @Max804: Lass Dir doch mal den Rückgabewert ausgeben.

Und wie kann ein `jahr` Wahr oder Unwahr sein? `jahr` sollte immer eine Zahl sein und nicht an `True` oder `False` gebunden werden.

Zudem ist das Ergebnis der ``if``-Bedinung ja bereits ein Wahrheitswert. Also brauch mal kein ``if`` sondern das Ergebnis ist schon das Ergebnis der Bedingung.

Die Klammern dort sind übrigens überflüssig und sollten Weg.

Und man sollte auch alle möglichen Varianten prüfen, nicht nur ein Schaltjahr und ein Nicht-Schaltjahr, auch die Fälle wo es wichtig ist, ob es durch 100/400 teilbar ist.
Hi,
meinst du so:

Code: Alles auswählen

def Schaltjahr(jahr):
    if (jahr % 4 == 0) and (jahr % 100 != 0) or (jahr % 400 == 0):
        Schaltjahr = True
    else: 
        Schaltjahr = False
    return Schaltjahr
So passt das bei der Kontrolle, aber ich glaube ich habe hier den Fall nicht drinne, wenn es nicht durch 100 teilbar ist, oder?
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

... und willkommen im Forum.

In der Funktion fehlt das `return`. Wenn du kein explizites return angibst wird implizit der Wert `None` (der Python Wert für nichts, umgangssprachlich) zurückgegeben. Und `assert None` gibt immer einen AssertionError.

Verknüpfte Prüfungen wie dein "(jahr % 4 == 0) and (jahr % 100 != 0) or (jahr % 400 == 0)" evaluiert Python von links nach recht und ist "lazy", d.h. es bricht die Prüfung, wenn sie nicht mehr zutreffen kann. In deinem Fall würde der letzte Schritte mit der Prüfung auf `... %400...` wegfallen, wenn die Divisionen durch 4 und 100 aufgehen. Weil bei `or` reicht es, wenn mindestens einer der beiden Werte wahr ist. Abgesehen davon stimmt deine Implementierte Logik hier nicht.

Musst du das in einer Zeile machen? Nicht unbedingt schöner, aber besser nachzuvollziehen ist es, wenn du eine verschachtelte if-Kaskade baust.

Außerdem überschreibst du den Eingabewert in dein Funktion, den Integerwert `jahr`, in deiner Funktion mit einem Bool'schen Wert. Das ist zumindest unerwartet und und führt zu Fehlern, wenn du später in der Funktion nochmal den Wert von Jahr brauchen würdest. Besser ist, dir eine eigene Variable anzulegen, die aussagekräftig ist, wie `ist_ein_schaltjahr`.

Gruß, noisefloor
Max804
User
Beiträge: 8
Registriert: Montag 28. November 2022, 18:43

noisefloor hat geschrieben: Montag 28. November 2022, 19:54 Hallo,

... und willkommen im Forum.

In der Funktion fehlt das `return`. Wenn du kein explizites return angibst wird implizit der Wert `None` (der Python Wert für nichts, umgangssprachlich) zurückgegeben. Und `assert None` gibt immer einen AssertionError.

Verknüpfte Prüfungen wie dein "(jahr % 4 == 0) and (jahr % 100 != 0) or (jahr % 400 == 0)" evaluiert Python von links nach recht und ist "lazy", d.h. es bricht die Prüfung, wenn sie nicht mehr zutreffen kann. In deinem Fall würde der letzte Schritte mit der Prüfung auf `... %400...` wegfallen, wenn die Divisionen durch 4 und 100 aufgehen. Weil bei `or` reicht es, wenn mindestens einer der beiden Werte wahr ist. Abgesehen davon stimmt deine Implementierte Logik hier nicht.

Musst du das in einer Zeile machen? Nicht unbedingt schöner, aber besser nachzuvollziehen ist es, wenn du eine verschachtelte if-Kaskade baust.

Außerdem überschreibst du den Eingabewert in dein Funktion, den Integerwert `jahr`, in deiner Funktion mit einem Bool'schen Wert. Das ist zumindest unerwartet und und führt zu Fehlern, wenn du später in der Funktion nochmal den Wert von Jahr brauchen würdest. Besser ist, dir eine eigene Variable anzulegen, die aussagekräftig ist, wie `ist_ein_schaltjahr`.

Gruß, noisefloor
Ich glaube jetzt habe ich es. Verschachtelt ist es auch anschaulicher.

Code: Alles auswählen

def Schaltjahr(jahr):
    if jahr % 4 == 0:
        if jahr % 100 == 0:
            if jahr % 400 == 0:
                Schaltjahr = True
            else: Schaltjahr = False
        else: Schaltjahr = True
    else: Schaltjahr = False
    return Schaltjahr
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

Hallo

Code: Alles auswählen

def is_leap(year):
    return bool(year%400==0 or year%4==0 and year%100)
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Max804: Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase). Und es ist verwirrend wenn man in einer Funktion einen lokalen Namen hat der genau wie die Funktion heisst. Es ist auch nicht notwendig das Ergebnis überhaupt an einen Namen zu binden, man kann das auch gleich an der Stelle zurück geben wo die Zuweisungen jetzt stehen.

Nach den Doppelpunkten solltest Du eine neue Zeile anfangen.

Ich finde es auch nicht wirklich übersichtlicher als es ohne ``if``/``else`` nur mit ``and`` und ``or`` auszudrücken. Du hattest es ja schon fast richtig.

@karolus: Was ist der Grund für das `bool` und den letzten Term nicht mit einer Zahl zu vergleichen? Das ist irgendwie so asymmetrisch so.

Code: Alles auswählen

def is_leap(year):
    return year % 400 == 0 or year % 4 == 0 and year % 100 != 0
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Max804
User
Beiträge: 8
Registriert: Montag 28. November 2022, 18:43

Hi,
wenn wir schon dabei sind: Ich soll ein Programm erstellen, dass Palindrome feststellt.

Code: Alles auswählen

def Palindrom(wort):
    if wort == wort[::-1]:
        Palindrom = True
    else:
        Palindrom = False
    return Palindrom
  

Code: Alles auswählen

assert not Palindrom('Test')
assert Palindrom('Lagerregal')
Der Code gibt wieder einen AssertionError. Ich habe mal geschaut was zurückgegeben wird, leider wird mir immer false zurückgegeben. Ich weiß nicht wieso. (Ich muss mit [::-1] arbeiten)
Benutzeravatar
Whitie
User
Beiträge: 216
Registriert: Sonntag 4. Juni 2006, 12:39
Wohnort: Schulzendorf

Na dann prüf doch mal was L == l ausgibt.
Max804
User
Beiträge: 8
Registriert: Montag 28. November 2022, 18:43

Whitie hat geschrieben: Montag 28. November 2022, 23:06 Na dann prüf doch mal was L == l ausgibt.
Ich verstehe, es liegt anscheinend an der Groß- und Kleinschreibung. Wenn alles klein ist funktioniert es. Groß- und Kleinschreibung soll aber keine Rolle spielen. Wie kann ich das aber umgehen?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Und schon wieder nennst Du Deine lokale Variablewie Deine Funktion und schon wieder schreibst du die Funktion und den variablen Namen mit einem Großbuchstaben. Beides macht man in Python nicht.
Schau mal, welche Methoden Strings kennen.
Max804
User
Beiträge: 8
Registriert: Montag 28. November 2022, 18:43

Sirius3 hat geschrieben: Montag 28. November 2022, 23:38 Und schon wieder nennst Du Deine lokale Variablewie Deine Funktion und schon wieder schreibst du die Funktion und den variablen Namen mit einem Großbuchstaben. Beides macht man in Python nicht.
Schau mal, welche Methoden Strings kennen.
Ich habe es so geschrieben, weil ich dachte es muss so sein wegen dem

Code: Alles auswählen

assert not Palindrom('Test')
assert Palindrom('Lagerregal')
Funktioniert es denn immernoch, wenn ich es z.B istPalindrom nenne?
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Es würde ist_palindrom heißen und warum sollte das nicht funktionieren?

Code: Alles auswählen

 def ist_palindrom(wort):
     return wort == wort[::-1]
Max804
User
Beiträge: 8
Registriert: Montag 28. November 2022, 18:43

Achso, ich habe es falsch verstanden. Wollte es defPalindrom(wort) lassen, aber dafür dann bei den if Bedingungen istPalindrom schreiben. Dachte das geht dann so.
Also:

Code: Alles auswählen

def Palindrom(wort):
    if wort.lower() == wort.lower()[::-1]:
        istPalindrom = True
    else:
        istPalindrom = False
    return istPalindrom
  

Code: Alles auswählen

assert not Palindrom('Test')
assert Palindrom('Lagerregal')
Sirius3 hat geschrieben: Montag 28. November 2022, 23:48 Es würde ist_palindrom heißen und warum sollte das nicht funktionieren?

Code: Alles auswählen

 def ist_palindrom(wort):
     return wort == wort[::-1]
[/quote]
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Funktionen sollten nach Tätigkeiten benannt sein, damit man weiß, was die Funktion macht. Bei `Palindrom` weiß man nicht, ob es ein Palindrom erzeugt, oder prüft, ob es ein Palindrom ist, oder irgend was anderes?
Funktionen und Variablennamen schreibt man immer komplett klein.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@Max804: bei Python gibt es eine Reihe von Konventionen bzgl. Schreibweisen und Benennungen. Ein paar haben die Sirius3 und __blackjack__ schon genannt. Daran solltest du dich auch tunlichst halten (tun eigentlich alle Python-Programmierer), weil da einfach zum guten Stil gehört und die Verständlichkeit von Python-Code (für alle) verbessert. Das ganze ist in der PEP 8 (https://peps.python.org/pep-0008/ hinterlegt. Solltest du einmal lesen, falls das bei dir in der Schule / im Kurs nie angesprochen wurde.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Falls dieser Stil, Funktionsnamen mit Grossbuchstaben am Anfang und Funktionsname noch mal als lokaler Name für das Ergebnis, vom Lehrer/Dozenten kommt, dann scheint der eigentlich BASIC oder Pascal statt Python schreiben zu wollen. Wer weiss was der noch so macht was nicht „pythonisch“ ist. 🤔
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
DeaD_EyE
User
Beiträge: 1021
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Eine Funktion, um ein Schaltjahr zu bestimmen, ist im Modul calendar enthalten:

Code: Alles auswählen

In [1]: import calendar

In [2]: calendar.isleap
Out[2]: <function calendar.isleap(year)>

In [3]: calendar.isleap??
Signature: calendar.isleap(year)
Source:
def isleap(year):
    """Return True for leap years, False for non-leap years."""
    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
File:      ~/.pyenv/versions/3.11.0/lib/python3.11/calendar.py
Type:      function
Wenn man mal irgendwas benötigt und die Python-Stdlib in- und auswendig kennt, kann man dort beim Code nachsehen.
Oftmals hat man auch das Problem, dass Module von Drittanbietern nicht dokumentiert sind. Dann kann man nach Projekten suchen, die dieses Modul einsetzen und kann davon lernen.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Max804
User
Beiträge: 8
Registriert: Montag 28. November 2022, 18:43

__blackjack__ hat geschrieben: Dienstag 29. November 2022, 10:01 Falls dieser Stil, Funktionsnamen mit Grossbuchstaben am Anfang und Funktionsname noch mal als lokaler Name für das Ergebnis, vom Lehrer/Dozenten kommt, dann scheint der eigentlich BASIC oder Pascal statt Python schreiben zu wollen. Wer weiss was der noch so macht was nicht „pythonisch“ ist. 🤔
Ja, ist vom Dozenten so, wir sollen auch nix ändern. Deswegen lasse ich es jetzt auch so.
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich würde ihn auf Style Guide for Python Code hinweisen. Und das Python weder BASIC noch Pascal ist. Die Namenskonventionen bezüglich der Gross-/Kleinschreibung transportiert Informationen, das ist nicht einfach nur Kosmetik. `Palindrom` oder `Schaltjahr` sind in dieser Schreibweise in Python für den Leser klar erkennbar Klassen und keine Funktionen. Wenn das nicht stimmt, dann ist das verwirrend. Insbesondere auch weil die Namen ja auch keine Tätigkeiten beschreiben, wie das bei Funktionen (und Methoden) üblich ist, sondern ”Dinge” und das auch noch mal auf Datentypen/Klassen hindeutet, denn die modellieren ja ”Dinge” im weitesten Sinn.

Und wenn man in einer Funktion noch mal den gleichen Namen lokal für einen Wert definiert, kann man keine rekursiven Aufrufe mehr machen, weil der Name der Funktion dann durch den lokalen Namen für einen anderen Wert verdeckt wird.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten