Boolesche Ausdrücke#

Boolsche Ausdrücke kann man ganz generell als “logische” Aussagen, die entweder wahr oder falsch sein können, verstehen. Wichtig ist, dass ein boolscher Ausdruck auf jeden Fall immer entweder ausschließlich 100% wahr oder ausschließlich 100% falsch ist. Niemals ist ein boolscher Ausdruck irgendwas dazwischen oder beides. Boolsche Ausdrücke gibt es übrigens nicht nur in Python, sondern diese sind elementarer Bestandteil in der Mathematik, Informatik und Logik. In Python können boolsche Ausdrücke in unterschiedlicher Form vorkommen, aber immer wenn Python einen boolschen Ausdruck sieht, dann versucht Python herauszufinden, ob die Aussage wahr oder falsh ist. Am Ende eines solchen Wahrheitsfindungsprozesses gibt Python dann entweder den Wert True oder den Wert False aus und sagt uns damit praktisch, ob der soeben evaluierte boolsche Ausdruck bzw. die Aussage True (wahr) oder False (falsch) ist.

Wie sieht denn nun ein solcher Boolscher Ausdruck in Python aus? Die einfachste und elementarste Form eines boolschen Ausdrucks sind die beiden Wahrheitswerte True und False selbst. Diese beiden Werte sind in Python Werte des Typs bool und nicht nur das Ergebnis einer jeden Evaluation boolscher Ausdrücke sondern für sich genommen eben selbst boolsche Ausdrücke. Evaluiert man die Aussage True auf ihren Wahrheitsgehalt, so kommt man natürlich selbst wieder auf das Ergebnis True. Evaluiert man die Aussage False auf ihren Wahrheitsgehalt, so kommt man natürlich auch hier wieder auf das Ergebnis False.

True
True
False
False

Vergleiche#

Man versteht am besten, was boolsche Ausdrücke sind, wenn man etwas über ihre elementarste (aber noch etwas inhaltslose) Existenzweise als True und False hinausgeht und sich anschaut, in welcher Form uns boolsche Ausdrücke in richtigen Programmen oft begegnen. Eine sehr wichtige Form boolscher Ausdrücke sind Vergleiche. In Vergleichen können wir zwei Werte bzw. Variablen miteinander vergleichen. Dabei stehen uns die typischen Vergleichsoperatoren, die dir bestimmt bekannt sind, zur Verfügung.

Ein Beispiel: Unten vergleiche ich die beiden Werte 1 und 2 daraufhin, ob 1 kleiner als 2 ist. Python führt für uns den Vergleich aus und gibt uns eine Antwort:

1 < 2
True

Wir können uns vorstellen, dass wir oben gerade Python gefragt haben, ob 1 kleiner als 2 ist. Python hat sich dann den Sachverhalt angenommen, die beiden Zahlen miteinander vergleichen und uns die Antwort ausgegeben. In diesem Fall war die Antwort “Ja, 1 ist kleiner als 2.” weshalb uns Python mit True geantwortet hat. Unten frage ich nun, ob 1 größer als 2 ist und Python antwortet uns dann diesmal natürlich mir False d.h. “nein”:

1 > 2
False

Wir können uns das Ganze aber nicht nur als Ja-Nein-Frage, sondern auch als eine von uns formulierte und von Python zu prüfende Aussage vorstellen. Wenn ich sage “1 ist kleiner als 2”, dann antwortet uns Python “ja, das stimmt”. Wenn ich sage, “1 ist größer als 2”, dann antwortet Python mit “nein, das ist falsch”.

In Python stehen uns neben den beiden Vergleichs-Operatoren < und > noch eine Menge weiterer Vergleichsoperatoren zur Verfügung. Hier eine Übersicht über die gängisten Vergleichsoperatoren:

Bedeutung

Symbol

kleiner

<

kleinergleich

<=

gleich

==

ungleich

!=

größergleich

>=

größer

>

Nicht alle Vergleichsoperatoren beziehen sich zwangsläufig auf Zahlen. So kann man mit dem ==-Operator z.B. auch prüfen, ob zwei Zeichenketten gleich sind:

"python" == "python"
True
"python" == "pyton"
False

Wir können damit aber auch z.B. prüfen, ob zwei Listen identisch sind:

[1, 2, 3] == [1, 2, 3]
True
[1, 2, 3] == [3, 2, 1]
False

Innerhalb von Bedingungen können wir natürlich auch alle möglichen Funktionen verwenden, z.B. die Funktion len():

len([1, 2, 3]) == 3
True

Abstrakte Variablen statt konkrete Werte#

In den obigen Beispielen habe ich die zu vergleichenden Werte immer direkt innerhalb des Vergleiches konkret ausformuliert. Das werden wir innerhalb eines richtigen Programmes aber eigentlich niemals in der Form tun. Stattdessen werden wir in den meisten Fällen innerhalb von Vergleichen bzw. allgemein innerhalb von boolschen Ausdrücken nicht alle Werte konkret ausschreiben, sondern Variablen als Platzhalter für konkrete Werte einfügen. Dadurch können wir dann Werte miteinander vergleichen, die wir zum Zeitpunkt des Programmierens nicht genau kennen, weil diese sich entweder aus einem sehr großen Datensatz ergeben oder sogar vielleicht erst “dynamisch” innerhalb unseres Programmes entstehen oder verändert werden. Erst wenn wir die Antwort nicht genau kennen, machen solche Vergleiche ja erst wirklich Sinn.

Unten im Beispiel gehe ich z.B. die Liste age_list durch und frage für jedes Element nach, ob dieses größer 40 ist. Das funktioniert, weil der Vergleich age > 40 diesmal nich nur direkt ausformulierte Werte, sondern u.a. die Variable age enthält. In jeder Runde des For-Loops bekommt die Variable age den Wert eines anderen Elementes der Liste age_list zugewiesen, sodass dieselbe “Vergleichsstruktur” für unterschiedliche konkrete Werte durchgeführt wird.

# Daten
age_list = [25, 39, 45, 61]

# Jeden Wert der Daten durchgehen
for age in age_list:
    # größer 40?
    print(age > 40)
False
False
True
True

Die logischen Operatoren NICHT, UND & ODER#

Mithilfe der Operatoren and, or und not können wir auch kompliziertere, verknüpfte Bedingungen aufstellen. Die Funktionsweise der drei Operatoren entspricht dabei der Funktionsweise der logischen Operatoren UND, ODER und NICHT der klassischen Aussagenlogik.

Ein Video zur klassichen Aussagenlogik und der grundlegenden Funktionsweise der logischen Operatoren bzw. Verknüpfungen findest du hier:

from IPython.display import YouTubeVideo
YouTubeVideo("inwIsNIaWJM")

Negation: not#

Das Wörtchen not ermöglicht uns “verneinte” Aussagen aufzustellen d.h. Aussagen, welche besagen, dass etwas nicht wahr ist. Ganz allgemein wird durch ein not aus jedem True ein False und aus jedem False ein True.

not True
False
not False
True
not not True
True

Wir könnten aber beispielsweise auch die Aussage “1 ist größer 0” mithilfe dem Schlüssel-Wort not in die Aussage “1 ist nicht größer 0” umwandeln:

not 1 > 0
False

Die Aussage “1 ist nicht größer 0” ist natürlich False. Wir können obige “Aussage” natürlich auch wieder als “Frage” lesen: “Ist 1 nicht größer 0?”. Darauf wäre die Antwort dann “Nein”.

Konjunktion: and#

Bisher haben wir immer nur “einfache” Aussagen aufgestellt (z.B. einen Vergleich auf einmal durchgeführt). Mithilfe von and und or können wir mehrere Aussagen gleichzeitig aufstellen und somit mehrere Teil-Aussagen zu einer Gesamt-Aussage verknüpfen (wir können dadurch z.B. mehrere Vergleiche auf einmal durchführen). Schauen wir uns an dieser Stelle zunächst die sogenannte UND-Verknüpfung an.

Der logische Operator and ermöglicht es uns, zwei Teilaussagen so zu verknüpfen, dass die Gesamtaussage genau dann wahr ist, wenn alle Teilaussagen wahr sind. Ich könnte beispielsweise gleichzeitig die Aussagen “1 ist größer 0” und “2 ist gleich 3” aufstellen. Wenn ich diese nun mit einem “und” verknüpfe, dann sage ich “1 ist größer 0 und 2 ist gleich 3”. Damit impliziere ich, dass ich für beide Aussagen annehme, dass sie wahr sind. Python überprüft das und sagt mir, ob es wahr ist, das beide Teil-Aussagen wahr sind:

1 > 0 and 2 == 3
False

Python sagt mir, dass die Aussage, dass beide Teil-Aussagen wahr sind, nicht stimmt. Das liegt daran, dass die Aussage “2 ist gleich 3” falsch ist, wodurch es auch nicht mehr stimmt, dass beide Teil-Aussagen wahr sind.

Immer wenn mehrere Teil-Aussagen zu einer Gesamt-Aussage verknüpft sind, dann geht Python Schritt für Schritt die Teil-Aussagen durch, prüft deren Wahrheitsgehalt, schaut dann, welche neue Aussage durch die “Lösung” der Teil-Aussagen entsteht und prüft dann diese. Je nach Anzahl von Teil-Aussagen oder Schachtelung von Teil-Aussagen, wird dieses Vorgehen mehrmals wiederholt. Aber egal, aus vielen Teil-Aussagen eine Gesamt-Aussage besteht, am Ende wird jede Gesamtaussage auf einen einzigen Wert reduziert: True oder False.

Schauen wir uns diese schrittweise Reduktion der obigen verknüpften Aussage mal Schritt für Schritt an. Im ersten Schritt “reduziert” Python den Ausdruck

1 > 0 and 2 == 3

zu

True and False

Zwei durch and verknüpfte Aussagen werden nur dann True, wenn beide Teil-Aussagen True sind. Daher wird aus

True and False

nun

False

weil nicht auf beiden Seiten des and ein True steht.

Da es bei der Verknüpfung von Aussagen durch and letztlich nur um Kombinationen von True und False geht, weil jede Aussage auf True oder False redziert wird, können wir Python für Demonstrationszwecke auch einfach direkt nach der “Wahrheit” verschiedener and-Verknüpfungen von True und False fragen, wie ich es im Folgenden tue:

True and True
True
True and False
False
False and True
False
False and False
False

Wir sehen, eine UND-Verknüpfung wird nur genau dann True, wenn beide Teil-Aussagen True sind.

Disjunktion: or#

Mit and können wir sehr detailreiche & spezifische Aussagen aufstellen bzw. fragen, die nur True sind, wenn auch alle Teil-Aussagen True sind. Dadurch können wir später sehr strenge Bedingungen aufstellen. Hingegen eignet sich der Operator or sehr gut, wenn wir etwas “lockerere” Bedingungen aufstellen wollen. Ein or verknüpft zwei Teil-Aussagen so, dass die Gesamtaussage genau dann wahr ist, wenn mindestens eine der beiden Teil-Aussagen wahr ist. Es kann also die eine, die andere oder beide Teil-Aussagen wahr sein, damit die Gesamt-Aussage wahr wird. Nur wenn beide Teil-Aussagen falsch sind, wird auch die Gesamt-Aussage falsch.

Verknüpft man z.B. die wahre Aussage “1 ist größer 0” und die falsche Aussage “2 ist gleich 3” mit einem or zur Aussage “1 ist größer 0 oder 2 ist gleich 3”, dann ist diese Gesamt-Aussage wahr, weil man mit einem or impliziert, dass es sein kann, dass nur eine von beiden Aussagen wahr ist.

Aus

1 > 0 or 2 == 3

wird

True or False

woraus dann

True

wird.

Die Aussage “1 ist größer 0 oder 2 ist gleich 3” ist also wahr, weil eine der Teilaussagen wahr ist.

Da or-verknüpfte Aussagen bzw. Bedingungen immer True sind, wenn mindestens eine der Teilaussagen True ist, wird die or-verknüpfte Gesamtaussage nur genau dann False, wenn beide Teilaussagen False sind. Dies kann man selbst überprüfen, wenn man alle möglichen or-Verknüpfungen von True und False von Python evaluieren lässt:

True or True
True
True or False
True
False or True
True
False or False
False

Wie dir vielleicht schon aufgefallen ist, hat ein “oder” innerhalb der klassichen Aussagenlogik eine leicht andere Bedeutung als ein “oder” in der Alltagssprache. In der Alltagssprache meinen wir mit “oder” typischerweise, dass wir erwarten, dass genau eine der beiden Aussagen wahr sein kann (entweder die eine oder die andere). In der Aussagenlogik bzw. hier in Python meinen wir mit “oder”, dass wir die Richtigkeit mindestens einer der beiden Aussagen erwarten. Das “oder”, das wir hier benutzen, nennt man übrigens auch “nichtausschließendes oder”. Das “oder” der Alltagssprache nennt man “ausschließendes oder”.

Mehrere Verknüpfungen#

Wir können natürlich auch mehrere and- und or-Verknüpfungen kombinieren, z.B.:

“2 ist gleich 2 oder 2 ist gleich 3 und 0 ist größer 1”

Diese Aussage sieht in Python-Code so aus:

2 == 2 or 2 == 3 and 0 > 1

Ist diese Aussage wahr oder falsch?

Fangen wir mal an, diese Aussage auf ihre Wahrheit zu evaluieren. Im ersten Schritt können wir alle Teil-Aussagen, die keine weiteren Verknüpfungen beinhalten, auf ihren Wahrheitswert reduzieren.

Aus

2 == 2 or 2 == 3 and 0 > 1

wird dadurch

True or False and False

Wie gehts nun aber weiter? Müssen wir zuerst die or-Verknüpfung oder die and-Verknüpfung evaluieren? Tatsächlich macht die Reihenfolge einen großen Unterschied!

Würden wir zuerst die and-Verknüpfung evaluieren, wird

True or False and False

zu

True or False

was dann schließlich zu

True

wird.

Würden wir hingegen zuerst die or-Verknüpfung evaluieren, würde

True or False and False

zu

True and False

werden, was dann ingesamt zu

False

führt.

Je nach Reihenfolge der Evaluation der Verknüpfungen wird die Gesamtaussage einmal wahr und einmal falsch. Jedoch ist die Priorität logischer Operatoren d.h. die Reihenfolge, in welcher die Operatoren evaluiert werden, festgelegt. So wie Punktrechnung vor Strichrechnung durchgeführt wird, wird das and immer vor dem or ausgeführt.

Daher wird die obige Beispielaussage insgesamt zu True:

2 == 2 or 2 == 3 and 0 > 1
True

Vollständigerweise lautet die Reihenfolge bzw. Priorotät der logischen Operatoren wie folgt:

  1. not

  2. and

  3. or

Das not bezieht sich also immer nur auf die unmittelbar dahinter stehende, einzelne und nicht weiter verknüpfte Aussage.

In diesem Beispiel würde sich das not also nur auf das True beziehen:

not True or False

Dadurch wird der Ausdruck erst zu

False or False

und dann zu

False

Des Weiteren gelten für logische Ausdrücke und deren Priorität auch die typischen Klammergesetze der Mathematik. So kann beispielsweise die Priorität des and vor dem or durch entsprechende Klammersetzung durchbrochen werden.

Das Keyword “in”#

Bedingungen können nicht nur mathematische Vergleiche beinhalten. Das super praktische Keyword in ermöglicht es uns z.B. zu erfragen, ob ein bestimmter Wert in einem sequentiellen Datentyp (z.B. Liste oder String) ist.

Fragen wir uns beispielsweise, ob der Wert 10 in der Liste [3, 2, 8, 1] vorkommt, können wir schreiben:

10 in [3, 2, 8, 1]
False

Die Aussage “Der Wert 10 befindet sich in der Liste [3, 2, 8, 1]” ist falsch, weshalb wir False ausgegeben bekommen.

Das Keyword in können wir auch benutzen, um zu erfragen, ob ein bestimmtes Symbol in einem String auftaucht. Hier frage ich z.B., ob das Symbol "n" im Wort "Python" ist:

"n" in "Python"
True