Sets in Python: Eindeutige Werte und blitzschnelle Lookups

Sets speichern jedes Element nur einmal und finden Werte extrem schnell. Wie du sie erstellst, mit Mengenoperationen kombinierst und wann sie die bessere Wahl gegenüber Listen sind.

Teilen

Listen und Dictionaries kennst du wahrscheinlich schon in- und auswendig. Aber es gibt in Python noch einen dritten Datentyp, der oft übersehen wird, obwohl er in vielen Situationen die eleganteste Lösung ist: das Set. Ein Set ist eine ungeordnete Sammlung, die jedes Element nur ein einziges Mal enthält – und das mit einer beeindruckenden Geschwindigkeit beim Nachschlagen. In diesem Beitrag schauen wir uns an, wie Sets funktionieren, warum sie so schnell sind und wann du sie einer Liste vorziehen solltest.

Was ist ein Set?

Ein Set ist eine ungeordnete Sammlung von eindeutigen Elementen. Zwei Eigenschaften machen es besonders: Es kann kein Element doppelt enthalten, und die Reihenfolge der Elemente ist nicht garantiert. Du erstellst ein Set mit geschweiften Klammern oder mit der Funktion set().

zahlen = {1, 2, 3, 3, 2, 1}
print(zahlen)  # {1, 2, 3} – Duplikate verschwinden automatisch

# Ein leeres Set braucht set(), NICHT {} – das wäre ein Dictionary!
leer = set()
print(type(leer))  # <class 'set'>

# Aus einer Liste ein Set machen
namen = set(["Anna", "Ben", "Anna", "Clara"])
print(namen)  # {'Anna', 'Ben', 'Clara'}

Achte auf das kleine Detail: {} erzeugt ein leeres Dictionary, kein leeres Set. Für ein leeres Set brauchst du immer set().

Sets erstellen und verändern

Sets sind veränderbar (mutable): Du kannst nachträglich Elemente hinzufügen und entfernen. Die wichtigsten Methoden dafür sind add(), remove() und discard().

sprachen = {"Python", "JavaScript"}

sprachen.add("Rust")        # einzelnes Element hinzufügen
sprachen.update(["Go", "C"]) # mehrere Elemente auf einmal

sprachen.discard("C")       # entfernt, wirft KEINEN Fehler wenn nicht vorhanden
sprachen.remove("Go")       # entfernt, wirft KeyError wenn nicht vorhanden

print(sprachen)  # z. B. {'Python', 'JavaScript', 'Rust'}

Der Unterschied zwischen remove() und discard() ist wichtig: remove() löst einen KeyError aus, wenn das Element fehlt, discard() bleibt still. Wenn du nicht sicher bist, ob ein Wert vorhanden ist, ist discard() die sichere Wahl.

Warum Sets so schnell sind

Der entscheidende Vorteil von Sets zeigt sich beim Prüfen, ob ein Element enthalten ist. Bei einer Liste muss Python im schlimmsten Fall jedes einzelne Element durchgehen – das dauert länger, je größer die Liste wird. Ein Set nutzt intern eine Hash-Tabelle, wodurch die Prüfung nahezu unabhängig von der Größe konstant schnell bleibt.

import time

daten_liste = list(range(1_000_000))
daten_set = set(daten_liste)

gesucht = 999_999

start = time.perf_counter()
gesucht in daten_liste   # muss fast alles durchsuchen
print("Liste:", time.perf_counter() - start)

start = time.perf_counter()
gesucht in daten_set     # direkter Zugriff über Hash
print("Set:  ", time.perf_counter() - start)

Der Unterschied ist dramatisch: Die Suche in der Liste kann tausendmal langsamer sein als im Set. In Fachsprache hat der in-Test bei Listen die Komplexität O(n), bei Sets im Schnitt O(1). Wenn du also oft prüfst, ob Werte vorkommen, ist ein Set fast immer die bessere Wahl.

Mengenoperationen: Vereinigung, Schnitt und Differenz

Hier spielen Sets ihre wahre Stärke aus. Du kannst sie wie mathematische Mengen kombinieren – mit Methoden oder mit kurzen Operatoren.

frontend = {"HTML", "CSS", "JavaScript"}
backend = {"JavaScript", "Python", "SQL"}

# Vereinigung: alles zusammen (ohne Duplikate)
print(frontend | backend)   # {'HTML', 'CSS', 'JavaScript', 'Python', 'SQL'}

# Schnittmenge: was in beiden vorkommt
print(frontend & backend)   # {'JavaScript'}

# Differenz: nur im Frontend, nicht im Backend
print(frontend - backend)   # {'HTML', 'CSS'}

# Symmetrische Differenz: in genau einem der beiden
print(frontend ^ backend)   # {'HTML', 'CSS', 'Python', 'SQL'}

Jeder Operator hat auch eine Methoden-Variante: union(), intersection(), difference() und symmetric_difference(). Die Operatoren sind kompakter, die Methoden dafür etwas besser lesbar – such dir aus, was zu deinem Stil passt.

Praktische Anwendungsfälle

Der wohl häufigste Einsatz von Sets ist das Entfernen von Duplikaten. Willst du aus einer Liste alle doppelten Einträge löschen, ist ein Set die kürzeste Lösung.

# Duplikate aus einer Liste entfernen
besuche = ["Anna", "Ben", "Anna", "Clara", "Ben", "Anna"]
eindeutig = list(set(besuche))
print(eindeutig)  # z. B. ['Ben', 'Clara', 'Anna'] – Reihenfolge nicht garantiert!

# Gemeinsame Elemente zweier Listen finden
kunden_a = ["u1", "u2", "u3", "u4"]
kunden_b = ["u3", "u4", "u5"]
gemeinsam = set(kunden_a) & set(kunden_b)
print(gemeinsam)  # {'u3', 'u4'}

Ein wichtiger Hinweis: Da Sets ungeordnet sind, geht beim Umwandeln in ein Set die ursprüngliche Reihenfolge verloren. Wenn dir die Reihenfolge wichtig ist, kombiniere Set und dict.fromkeys(), das seit Python 3.7 die Reihenfolge bewahrt: list(dict.fromkeys(besuche)).

frozenset: Das unveränderliche Set

Manchmal brauchst du ein Set, das sich nach dem Erstellen nicht mehr ändern lässt – etwa als Schlüssel in einem Dictionary oder als Element eines anderen Sets. Dafür gibt es das frozenset. Es verhält sich wie ein normales Set, unterstützt aber keine verändernden Methoden.

berechtigungen = frozenset(["lesen", "schreiben"])

# frozensets sind hashbar und dürfen daher als dict-Schlüssel dienen
rollen = {
    frozenset(["lesen"]): "Gast",
    frozenset(["lesen", "schreiben"]): "Redakteur",
}
print(rollen[berechtigungen])  # Redakteur

# berechtigungen.add("löschen")  # AttributeError – nicht erlaubt

Ein normales Set ist nicht hashbar und kann deshalb weder als Dictionary-Schlüssel noch als Set-Element verwendet werden. Genau diese Lücke füllt das frozenset.

Fazit

Sets sind ein unterschätztes Werkzeug in Python. Immer wenn du eindeutige Werte brauchst, häufig auf Enthaltensein prüfst oder Sammlungen miteinander vergleichen willst, sind sie schneller und ausdrucksstärker als Listen. Merke dir die Faustregel: Geht es um Zugehörigkeit und Eindeutigkeit, nimm ein Set – geht es um Reihenfolge und Index-Zugriff, bleib bei der Liste. Probiere beim nächsten Duplikat-Problem einfach mal set() aus und beobachte, wie viel kürzer dein Code wird.