range Funktion mit step springt zu weit

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
cheers
User
Beiträge: 18
Registriert: Samstag 31. Juli 2021, 08:53
Wohnort: Deutschland

Hallo,
derzeit arbeite ich an einem kurzen Code der die Schaltjahre von 1600-2015 auswerfen soll.
An der Programmlogik tu ich mir noch etwas schwer, das passt noch nicht, aber egal wie ich es aufbaue, Python springt bei Jahrhundertwechseln nicht wie angegeben 4 Einheiten, sondern 8.
Das der Code zu dem was ich machen will, nicht richtig ist, weiß ich, daran bastel ich noch, ich verstehe aber nicht warum er statt der angegebenen 4 Jahre, teilweise 8 springt, die 4 soll er ja immer springen, egal welche Bedingung und jeden intervall den er springt auch ausgeben, also 1600,1604,1608 usw.:

for i in range (1600,2015,4):
if i % 100 and i % 400:
print(i,"das ist ein Schaltjahr")


Nur mal so als Beispiel wie er durchgeht:
(1600 wird übersprungen)
1604 das ist ein Schaltjahr
1608 das ist ein Schaltjahr
1612 das ist ein Schaltjahr
1616 das ist ein Schaltjahr
1620 das ist ein Schaltjahr
1624 das ist ein Schaltjahr
1628 das ist ein Schaltjahr
1632 das ist ein Schaltjahr
1636 das ist ein Schaltjahr
1640 das ist ein Schaltjahr
1644 das ist ein Schaltjahr
1648 das ist ein Schaltjahr
1652 das ist ein Schaltjahr
1656 das ist ein Schaltjahr
1660 das ist ein Schaltjahr
1664 das ist ein Schaltjahr
1668 das ist ein Schaltjahr
1672 das ist ein Schaltjahr
1676 das ist ein Schaltjahr
1680 das ist ein Schaltjahr
1684 das ist ein Schaltjahr
1688 das ist ein Schaltjahr
1692 das ist ein Schaltjahr
1696 das ist ein Schaltjahr
1704 das ist ein Schaltjahr

1708 das ist ein Schaltjahr
1712 das ist ein Schaltjahr
1716 das ist ein Schaltjahr
1720 das ist ein Schaltjahr
1724 das ist ein Schaltjahr
1728 das ist ein Schaltjahr
1732 das ist ein Schaltjahr
1736 das ist ein Schaltjahr
1740 das ist ein Schaltjahr
1744 das ist ein Schaltjahr
1748 das ist ein Schaltjahr
1752 das ist ein Schaltjahr
1756 das ist ein Schaltjahr
1760 das ist ein Schaltjahr
1764 das ist ein Schaltjahr
1768 das ist ein Schaltjahr
1772 das ist ein Schaltjahr
1776 das ist ein Schaltjahr
1780 das ist ein Schaltjahr
1784 das ist ein Schaltjahr
1788 das ist ein Schaltjahr
1792 das ist ein Schaltjahr
1796 das ist ein Schaltjahr
1804 das ist ein Schaltjahr
1808 das ist ein Schaltjahr
1812 das ist ein Schaltjahr
1816 das ist ein Schaltjahr
1820 das ist ein Schaltjahr
1824 das ist ein Schaltjahr
1828 das ist ein Schaltjahr
1832 das ist ein Schaltjahr
1836 das ist ein Schaltjahr
1840 das ist ein Schaltjahr
1844 das ist ein Schaltjahr
1848 das ist ein Schaltjahr
1852 das ist ein Schaltjahr
1856 das ist ein Schaltjahr
1860 das ist ein Schaltjahr
1864 das ist ein Schaltjahr
1868 das ist ein Schaltjahr
1872 das ist ein Schaltjahr
1876 das ist ein Schaltjahr
1880 das ist ein Schaltjahr
1884 das ist ein Schaltjahr
1888 das ist ein Schaltjahr
1892 das ist ein Schaltjahr
1896 das ist ein Schaltjahr
1904 das ist ein Schaltjahr

1908 das ist ein Schaltjahr
1912 das ist ein Schaltjahr
1916 das ist ein Schaltjahr
1920 das ist ein Schaltjahr
1924 das ist ein Schaltjahr
1928 das ist ein Schaltjahr
1932 das ist ein Schaltjahr
1936 das ist ein Schaltjahr
1940 das ist ein Schaltjahr
1944 das ist ein Schaltjahr
1948 das ist ein Schaltjahr
1952 das ist ein Schaltjahr
1956 das ist ein Schaltjahr
1960 das ist ein Schaltjahr
1964 das ist ein Schaltjahr
1968 das ist ein Schaltjahr
1972 das ist ein Schaltjahr
1976 das ist ein Schaltjahr
1980 das ist ein Schaltjahr
1984 das ist ein Schaltjahr
1988 das ist ein Schaltjahr
1992 das ist ein Schaltjahr
1996 das ist ein Schaltjahr
2004 das ist ein Schaltjahr

2008 das ist ein Schaltjahr
2012 das ist ein Schaltjahr

Auch wenn ich sage:
for i in range (1600,2015,4):
if i % 400:
print(i,"habefertig")


überspringt er die Jahrhundertgrenzen immer mit 8 statt 4 Schritten. Ist das ein Problem mit meiner range Funktion oder evtl etwas mit meinem Interpreter, ich nutze Spyder. Ich kann mir nicht annähernd erklären warum er genau bei den Jahrhunderten aus 4 dann 8 Jahre macht, die er springt.
:arrow: Viele Grüße und allen eine gute Zeit! :)
einfachTobi
User
Beiträge: 512
Registriert: Mittwoch 13. November 2019, 08:38

Es wird nichts übersprungen. Es erfolgt lediglich keine Ausgabe, weil deine Bedingungen nicht korrekt formuliert sind. Dass die richtigen Zahlen ankommen, kannst du ganz leicht auswerten:

Code: Alles auswählen

for i in range(1600, 1808, 4):
    print(i, i % 100, i % 400)
Fällt dir was auf? Schau dir die Bedingungen für ein Schaltjahr noch mal an und schaue auch darauf, wie du diese prüfst.
cheers
User
Beiträge: 18
Registriert: Samstag 31. Juli 2021, 08:53
Wohnort: Deutschland

Okay, das ist ein interessanter Hinweis auf mein Problem. Ich versuch das gleich nochmal nachzustellen, also, zum Schaltjahr habe ich mir aufgeschrieben:
Schaltjahr = alle 4 Jahre
lässt sich das Jahr durch 100 teilen, ist es kein Schaltjahr.
lässt sich das Jahr durch 400 und 100 teilen ist es ein Schaltjahr
auch wenn es sich durch 400 teilen lässt ist es ein Schaltjahr

Ich habe Probleme damit herauszufinden wie der logisch richtige Aufbau sein muss, damit er mir das richtig durchläuft, hier einer der Codes die ich getestet habe:
for i in range (1600,2015,4):
if i % 400 and i % 100:
print(i, "Das ist ein Schaltjahr")
if i % 400:
print(i, "Das ist ein Schaltjahr")
if i % 100:
print(i, "Das ist kein Schaltjahr")


Da fiel mir das Problem auch schon auf, ich habe hier 2x die Bedingung mod. 100 stehen, einmal mit "Es ist ein Schaltjahr" und einmal ohne, klar dass das Probleme macht, ich weiß nur noch nicht wie ich das Abfange, sobald eine der Bedingungen erfüllt ist, abbrechen und Ergebnis ausgeben und nicht weiter durchgehen. Ich habe es im Verdacht mit Break/Continue versucht, dass ist aber wohl auch die falsche Spur. ich hatte es zu Beginn auch mit elif versucht.
:arrow: Viele Grüße und allen eine gute Zeit! :)
Sirius3
User
Beiträge: 18250
Registriert: Sonntag 21. Oktober 2012, 17:20

`i` ist ein sehr schlechter Name für ein Jahr. Benenne Deine Variablen, so, dass man gleich beim Lesen versteht, für was die Variable steht.
Gerade bei mathematischen Formeln ist es lesbarer, wenn man nicht implizit das "0 als False und alles andere als True" nimmt, sondern explizit vergleicht:

Code: Alles auswählen

for year in range(1600, 2015, 4):
    if year % 100 != 0 and year % 400 != 0:
        print(year, "das ist ein Schaltjahr")
Und wie lautet nun die Regel dafür, dass ein Jahr kein Schaltjahr ist, dann mußt Du diese Regel nur noch negieren.
cheers
User
Beiträge: 18
Registriert: Samstag 31. Juli 2021, 08:53
Wohnort: Deutschland

Ja korrekt, die Variable hätte ich gleich richtig benennen sollen, da geht man als Neuling zu stark nach den Vorgaben die es allgemein gibt um eine Funktion zu erklären. Das übernehme ich mir gleich. Das mit den Operatoren, darüber hab ich auch schon nachgedacht, ob ich das so irgendwie abfangen kann, mir fiel nur nicht ein wie... naja, nach 5h über dem selben Problem wird auch irgendwann einheitsdenken :D ich bastel mal weiter und wenn ich eine Lösung habe die funktioniert, poste ich die dann auch. Mercì für die Denkanstöße :)
:arrow: Viele Grüße und allen eine gute Zeit! :)
cheers
User
Beiträge: 18
Registriert: Samstag 31. Juli 2021, 08:53
Wohnort: Deutschland

so, das ist jetzt mein stand, es funktioniert soweit wenn ich das richtig gesehen habe, ich hatte am Ende noch Probleme die Ausnahmefälle 1600 und 2000 abzufangen, weil die den üblichen Regeln für Schaltjahre widersprechen. Sie sind sowohl durch 100, 4 und 400 teilbar, üblicherweise sind alle Jahreszahlen die durch 100 teilbar sind, keine Schaltjahre.

Vielen Dank für die rasche Hilfe :)

Code: Alles auswählen

for jahr in range(1600,2015,4):
    if jahr is 1600 and 2000: 
        pass
    elif jahr % 4 == 0 and jahr % 100 != 0:
        print(jahr,"Schaltjahr")
    elif jahr % 400 == 0:
        print(jahr, "Schaltjahr")
    elif jahr % 100 == 0:
        print(jahr,"Kein Schaltjahr")
    elif jahr % 100 != 0:
        print(jahr,"Schaltjahr")

Meine Ausgabe ist dann:

1600 Schaltjahr
1604 Schaltjahr
1608 Schaltjahr
1612 Schaltjahr
1616 Schaltjahr
1620 Schaltjahr
1624 Schaltjahr
1628 Schaltjahr
1632 Schaltjahr
1636 Schaltjahr
1640 Schaltjahr
1644 Schaltjahr
1648 Schaltjahr
1652 Schaltjahr
1656 Schaltjahr
1660 Schaltjahr
1664 Schaltjahr
1668 Schaltjahr
1672 Schaltjahr
1676 Schaltjahr
1680 Schaltjahr
1684 Schaltjahr
1688 Schaltjahr
1692 Schaltjahr
1696 Schaltjahr
1700 Kein Schaltjahr
1704 Schaltjahr
1708 Schaltjahr
1712 Schaltjahr
1716 Schaltjahr
1720 Schaltjahr
1724 Schaltjahr
1728 Schaltjahr
1732 Schaltjahr
1736 Schaltjahr
1740 Schaltjahr
1744 Schaltjahr
1748 Schaltjahr
1752 Schaltjahr
1756 Schaltjahr
1760 Schaltjahr
1764 Schaltjahr
1768 Schaltjahr
1772 Schaltjahr
1776 Schaltjahr
1780 Schaltjahr
1784 Schaltjahr
1788 Schaltjahr
1792 Schaltjahr
1796 Schaltjahr
1800 Kein Schaltjahr
1804 Schaltjahr
1808 Schaltjahr
1812 Schaltjahr
1816 Schaltjahr
1820 Schaltjahr
1824 Schaltjahr
1828 Schaltjahr
1832 Schaltjahr
1836 Schaltjahr
1840 Schaltjahr
1844 Schaltjahr
1848 Schaltjahr
1852 Schaltjahr
1856 Schaltjahr
1860 Schaltjahr
1864 Schaltjahr
1868 Schaltjahr
1872 Schaltjahr
1876 Schaltjahr
1880 Schaltjahr
1884 Schaltjahr
1888 Schaltjahr
1892 Schaltjahr
1896 Schaltjahr
1900 Kein Schaltjahr
1904 Schaltjahr
1908 Schaltjahr
1912 Schaltjahr
1916 Schaltjahr
1920 Schaltjahr
1924 Schaltjahr
1928 Schaltjahr
1932 Schaltjahr
1936 Schaltjahr
1940 Schaltjahr
1944 Schaltjahr
1948 Schaltjahr
1952 Schaltjahr
1956 Schaltjahr
1960 Schaltjahr
1964 Schaltjahr
1968 Schaltjahr
1972 Schaltjahr
1976 Schaltjahr
1980 Schaltjahr
1984 Schaltjahr
1988 Schaltjahr
1992 Schaltjahr
1996 Schaltjahr
2000 Schaltjahr
2004 Schaltjahr
2008 Schaltjahr
2012 Schaltjahr
:arrow: Viele Grüße und allen eine gute Zeit! :)
Sirius3
User
Beiträge: 18250
Registriert: Sonntag 21. Oktober 2012, 17:20

@cheers: Zahlen vergleicht man nicht mit `is` und `and` bedeutet etwas anderes, als Du denkst, was Du eigentlich wolltest ist der in-Operator:

Code: Alles auswählen

if jahr in [1600, 2000]
Das willst Du aber auch nicht, weil spätestens 2400 funktioniert Dein Code wieder nicht.
Dann wird aber für diese Jahre nicht ausgegeben, dass es sich um Schaltjahre handelt. Dank Deiner fehlerhaften Abfrage funktioniert die Funktion also zufälligerweise.
Wenn man eine lange elif-Kette hat, ist es immer gut, einen else-Block zu haben, der immer ausgeführt wird, und im Zweifel eine Exception erzeugt, damit man merkt, dass man irgendeinen Fall doch nicht berücksichtigt hat.

Code: Alles auswählen

    if jahr % 4 == 0 and jahr % 100 != 0:
        print(jahr, "Schaltjahr")
    elif jahr % 400 == 0:
        print(jahr, "Schaltjahr")
    elif jahr % 100 == 0:
        print(jahr, "Kein Schaltjahr")
    elif jahr % 100 != 0:
        print(jahr, "Schaltjahr")
    else:
        raise RuntimeError("da ging wohl was schief")
Bei Dir ist es aber so, dass die letzte Bedinung genau das Gegenteil der vorletzten Bedingung ist, so dass der letzte Block eigentlich der else-Block ist.

Code: Alles auswählen

    if jahr % 4 == 0 and jahr % 100 != 0:
        print(jahr, "Schaltjahr")
    elif jahr % 400 == 0:
        print(jahr, "Schaltjahr")
    elif jahr % 100 == 0:
        print(jahr, "Kein Schaltjahr")
    else:
        print(jahr, "Schaltjahr")
Wenn man aber nun die ganzen Bedingungen genau anschaut, prüfst Du am Anfang auf nicht durch 100 teilbar und ganz am Ende nochmal nicht durch 100 teilbar. Die zusätzliche Bedinung "durch 4 teilbar" wird also gar nicht gebraucht, das läßt sich also vereinfachen zu

Code: Alles auswählen

    if jahr % 100 != 0:
        print(jahr, "Schaltjahr")
    elif jahr % 400 == 0:
        print(jahr, "Schaltjahr")
    else:
        print(jahr, "Kein Schaltjahr")
Die ersten beiden Blöcke enthalten den selben Code, können also per or zusammengefasst weden:

Code: Alles auswählen

    if jahr % 100 != 0 or jahr % 400 == 0:
        print(jahr, "Schaltjahr")
    else:
        print(jahr, "Kein Schaltjahr")
Nun stimmt es aber nicht, dass alles Schaltjahre sind, die nicht durch 100 teilbar sind.
Du mußt nochmal genau schauen, wie die Bedingung richtigt lautet.
cheers
User
Beiträge: 18
Registriert: Samstag 31. Juli 2021, 08:53
Wohnort: Deutschland

das mit den schaltjahren hab ich auf verschiedenen seiten so gefunden, die sich einig waren, was durch 100 restlos teilbar ist, ist kein schaltjahr bis auf die ausnahmejahr 2000 und 1600 -für meinen zeitbereich jetzt-

das mit der exception kam in dem buch noch nicht dran und wird erst nach dieser aufgabe angesprochen, daher kannte ich die anwendung noch nicht. oftmals tu ich mir noch mit der syntax schwer, wie python das denn nun haben will. ich schau mir deine anmerkungen morgen früh wenn ich frisch bin nochmal genauer an, für heute ist es gut mit dem teil. Ich les jetzt erstmal noch weiter theorie.
:arrow: Viele Grüße und allen eine gute Zeit! :)
Sirius3
User
Beiträge: 18250
Registriert: Sonntag 21. Oktober 2012, 17:20

Für Deine Lebensspanne gibt es überhaupt keine Ausnahmen, außer vielleicht 2100, wenn Du so alt wirst. Also könnte man auch einfach schreiben, dass jedes durch 4 teilbare Jahr ein Schaltjahr ist. Das dumme ist nur, dass es falsch ist, und dazu geführt hat, dass vor ein paar hundert Jahren einfach so ein paar Tage im Kalender fehlen. Zufällig richtig ist also eigentlich falsch, genauso wie es stimmt, dass alle ungeraden Zahlen bis auf die 9 und 15 Primzahlen sind: 3, 5, 7, 11, 13, 17, 19, ...
cheers
User
Beiträge: 18
Registriert: Samstag 31. Juli 2021, 08:53
Wohnort: Deutschland

@Sirius3
ich hab mir einen Teil deiner Vorschläge zu Herzen genommen und den Code nochmal so angepasst, dass er allgemeingültig ist. Weiterhin hab ich das mit der else abfrage eingeführt, dass mir bei 1-2 testversuchen auch tatsächlich zeigte, dass irgendwas nicht "angesprungen" ist, von meinen Bedinungen. Ja ich kann das Sicher zusammenfassen, aber solang der Code jetzt erstmal grundlegend richtig ist, wäre ich für den Anfang zufrieden damit :)

Code: Alles auswählen

for jahr in range(1600,2400,4):
    if jahr % 4 == 0 and jahr % 400 == 0 and jahr % 100 == 0:
        print(jahr,"Schaltjahr")
    elif jahr % 4 == 0 and jahr % 400 != 0 and jahr % 100 == 0:
        print(jahr,"kein Schaltjahr")
    elif jahr % 4 == 0 and jahr % 100 != 0:
        print(jahr,"Schaltjahr")    
    elif jahr % 400 == 0:
        print(jahr,"Schaltjahr")
    else:
        print("alles funktioniert, nur nicht das hier... ")
:arrow: Viele Grüße und allen eine gute Zeit! :)
Sirius3
User
Beiträge: 18250
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn jahr % 400 = 0 ist, dann ist automatisch auch jahr % 4 == 0 und jahr % 100 == 0.
Wenn die erste Bedingung nicht wahr ist, ist automatisch jahr % 400 != 0, das bedeutet, diese Abfrage kann beim zweiten if entfallen.
Wenn die zweite if-Bedingung nicht wahr ist, ist automatisch jahr % 100 != 0, das bedeutet, diese Abfrage kann beim dritten if entfallen.
Das vierte if kann ganz weg, da dieser Fall schon mit dem ersten if abgedeckt ist.

Code: Alles auswählen

for jahr in range(1600,2400,4):
    if jahr % 400 == 0:
        print(jahr, "Schaltjahr")
    elif jahr % 100 == 0:
        print(jahr, "kein Schaltjahr")
    elif jahr % 4 == 0:
        print(jahr, "Schaltjahr")    
    else:
        print(jahr, "kein Schaltjahr")
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Dabei könnte man jetzt noch berücksichtigen, dass der "else" - Zweig nie durchlaufen wird:

Code: Alles auswählen

for jahr in range(1600, 2400, 4):
    if jahr % 400 == 0:
        print(f"{jahr} Schaltjahr")
    elif jahr % 100 == 0:
        print(f"{jahr} kein Schaltjahr")
    else:
        print(f"{jahr} Schaltjahr")    
Dabei stört dann, dass 'if' und 'else' das gleiche tun. Also:

Code: Alles auswählen

for jahr in range(1600, 2400, 4):
    if jahr % 100 == 0 and not jahr % 400 == 0:
        print(f"{jahr} kein Schaltjahr")
    else:
        print(f"{jahr} Schaltjahr")    
Sirius3
User
Beiträge: 18250
Registriert: Sonntag 21. Oktober 2012, 17:20

@rogerb: ich habe die Abfrage nach Teilbarkeit durch 4 explizit drin, weil der nächste, der das benutzt, nimmt die 4 im Range raus und erlebt eine Überraschung.
karolus
User
Beiträge: 144
Registriert: Samstag 22. August 2009, 22:34

Hallo

Und dann noch alles als Zweizeiler mit der ganzen Logik innerhalb einer f{…} klammer:

Code: Alles auswählen

for jahr in range(1600, 2401, 4):
    print(f'{jahr} ist { "k" if jahr%100 == 0 and jahr%400 else "" }ein Schaltjahr')
edit:
sirius hat geschrieben:@rogerb: ich habe die Abfrage nach Teilbarkeit durch 4 explizit drin, weil der nächste, der das benutzt, nimmt die 4 im Range raus und erlebt eine Überraschung.
Der Einwand ist berechtigt, daher nochmal ohne 'step4':

Code: Alles auswählen

for jahr in range(1600, 2401):
    print(f'{jahr} ist { "k" if ( jahr%100 == 0 and jahr%400 ) or jahr%4 else "" }ein Schaltjahr')
Zuletzt geändert von karolus am Freitag 13. August 2021, 09:25, insgesamt 1-mal geändert.
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Sirius3,
ich habe die Abfrage nach Teilbarkeit durch 4 explizit drin
klar, hab ja auch "könnte" geschrieben.

Bei solchen Minimalbeispielen ohne Kontext ist sowieso alles möglich...
Benutzeravatar
__blackjack__
User
Beiträge: 13998
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Als vergleich die `isleap()`-Funktion aus dem `calendar`-Modul aus der Python-Standardbibliothek:

Code: Alles auswählen

In [62]: 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:      /usr/lib/python3.6/calendar.py
Type:      function
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Antworten