Exkurs: Modulo#

Weil wir sowieso gerade dabei sind, relativ kompliziertes Zeug zu besprechen, schauen wir uns nun noch den Modulo an. Dieser hat nicht zwingend etwas mit Loops zu tun, kann aber sehr praktisch innerhalb von Loops sein. Der Modulo gibt uns den Rest einer “Division mit Rest” zurück. Teilt man beispielsweise 5 durch 2, dann “passt” die 2 genau zwei mal vollständig in die 5. Es bleibt aber ein ungeteilter Rest von 1. Dieser Rest entspricht dem Wert, der durch den Modulo-Operator zurückgegeben wird.

Der Modulo-Operator wird in Python durch das Prozentzeichen % dargestellt. Wenn man den Rest einer Division haben möchte, dann setzt man einfach an die Stelle, wo bei einer “normalen” Division der Divisions-Operator / stehen würde, den Modulo-Operator %.

Der Rest von “5 geteilt durch 2” ist wie gesagt 1. So würden wir diesen Rest in Python erhalten:

5 % 2
1

5 % 5 ergibt beispielsweise 0, da kein Rest zurück bleibt:

5 % 5
0

Was ist, wenn die teilende Zahl (Divisor) größer ist als die zu teilende Zahl (Dividend)? Dann bekommen wir den gesamten Dividenden zurück, da der Divisor ja kein einziges mal in den Dividenden passt, sodass der gesamte Dividend ungeteilt als Rest zurückbleibt. Beispiel: Der Rest von “3 geteilt durch 5” ist 3, da die 5 kein einziges mal vollständig in die 3 passt und somit die gesamte 3 als unteilbarer Rest zurück bleibt:

3 % 5
3

Eine gute Erklärung des Modulo findet ihr auch in diesem Video:

YouTubeVideo("rVGrds7AbPw")

Und wofür brauchen wir das Ganze? Der Modulo-Operator ist praktisch, wenn man beispielsweise automatisiert aufsteigend zählen möchte, aber ab einem bestimmten Wert automatisch immer wieder bei 0 anfangen möchte.

Ein Beispiel: Angenommen wir wollen immer wieder “0 1 2”, “0 1 2”, “0 1 2” zählen - also nach drei Zahlen immer wieder bei der 0 anfangen zu zählen. Mit dem Modulo-Operator und einem For-Loop können wir das ganz einfach machen:

for i in range(9):
    print(i % 3)
0
1
2
0
1
2
0
1
2

Warum funktioniert das? In jedem Schritt wird der Rest der “Division mit Rest” von i / 3 ermittelt. Und i steigt im Verlauf des For-Loops von 0 auf 8. Gehen wir kurz ein paar Schritte des For-Loops durch:

  1. Im ersten Schritt wird der Rest von 0 / 3 gesucht. Dieser ist 0.

  2. In der zweiten Runde des Loops wird der Rest von 1 / 3 gesucht, also 1.

  3. In der dritten Runde wird der Rest von 2 / 3 gesucht, also 2.

  4. In der vierten Runde wird der Rest von 3 / 3 gesucht, also? 0!

  5. In der fünften Runde wird der Rest von 4 / 3 gesucht, also 1.

  6. In der sechsten Runde wird der Rest von 5 / 3 gesucht, also 2.

  7. in der siebten Runde wird der Rest von 6 / 3 gesucht und wir sind wieder bei der 0!

Und so weiter…

Wir sehen, es wird immer so lange aufsteigend gezählt, bis bei der “Division mit Rest” kein Rest mehr übrig bleibt. Dann geht es wieder von 0 los. Hier nochmal eine modifzierte Variante des obigen For-Loops:

for i in range(9):
    print("Der Rest von", i, "/ 3 ist", i % 3)
Der Rest von 0 / 3 ist 0
Der Rest von 1 / 3 ist 1
Der Rest von 2 / 3 ist 2
Der Rest von 3 / 3 ist 0
Der Rest von 4 / 3 ist 1
Der Rest von 5 / 3 ist 2
Der Rest von 6 / 3 ist 0
Der Rest von 7 / 3 ist 1
Der Rest von 8 / 3 ist 2

Okay, und wofür brauchen das jetzt? Eine mögliche Anwendung des Modulo liegt für uns im Bereich der Listenindizierung. Angenommen wir haben - warum auch immer - eine stetig aufsteigende Zahl, die wir als Index für einen Listenzugriff verwenden. Doch sobald diese Zahl höher als der höchste Index der Liste ist, enteht ein Fehler. Wie z.B. hier:

liste = ["hallo", "was", "geht"]
for i in range(10):
    index = i
    print(liste[index])
hallo
was
geht
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-55-045d77d229d9> in <module>
      2 for i in range(10):
      3     index = i
----> 4     print(liste[index])

IndexError: list index out of range

Mit dem Modulo-Operator kann man nun erreichen, dass der Index immer wieder auf 0 gesetzt wird, sobald dieser gleich der Länge der Liste ist. Die Länge der Liste ist ja gleich dem ersten “ungültigen” Index (Weil der höchste Index einer Liste gleich der Länge der Liste minus 1 ist. Der letzte bzw. höchste Index einer Liste der Länge 4 ist z.B. die 3.). Wir bekommen nun immer einen gültigen Index, wenn wir die Schleifenvariable “modulo” der Länge der Liste nehmen. Dadurch wird der Index immer wieder im richtigen Moment, d.h. wenn der Index den höchst möglichen Index erreicht hat, auf 0 gesetzt.

liste = ["hallo", "was", "geht"]
for i in range(10):
    index = i % len(liste)
    print(liste[index])
hallo
was
geht
hallo
was
geht
hallo
was
geht
hallo