Zum Inhalt springen

Sammlungen unterstĂŒtzen typischerweise:

  • Iteration (for element in sammlung)
  • MitgliedschaftsprĂŒfung (x in sammlung)
  • LĂ€ngenbestimmung (len(sammlung))
  • Zugriff per Index oder SchlĂŒssel (wenn geordnet oder assoziativ)

Python hat keine strikte „Sammlungs-Schnittstelle“, folgt aber informellen Protokollen. Wenn ein Objekt __iter__, __len__, __contains__ implementiert, gilt es als Sammlung.


Was KEINE Sammlung ist

Folgende Typen sind keine Sammlungen, da sie keine Gruppen von Elementen enthalten:

  • int, float, bool — Skalarwerte
  • None — Fehlen eines Werts
  • Funktionen, Module, Klassen — sind Objekte, aber keine Datencontainer (es sei denn, sie enthalten __dict__)

Eingebaute Sammlungen

Ohne Import verfĂŒgbar:

TypBeschreibung
listGeordnete, verÀnderbare Sequenz.
tupleGeordnete, unverÀnderbare Sequenz.
dictGeordnete SchlĂŒssel-Wert-Zuordnung (seit Python 3.7).
setUngeordnete Sammlung eindeutiger Elemente.
frozensetUnverÀnderbare Version von set.

Erweiterte Sammlungen aus der Standardbibliothek

TypModulZweck
SimpleNamespacetypesObjekt mit dynamischen Attributen (Alternative zu dict mit Punktzugriff).
namedtuplecollectionsUnverÀnderbares Tupel mit benannten Feldern.
dequecollectionsDoppelseitige Warteschlange — effizient fĂŒr Operationen an beiden Enden.
CountercollectionsSubklasse von dict zum ZĂ€hlen von Objekten.
defaultdictcollectionsWörterbuch mit Standardwerten fĂŒr fehlende SchlĂŒssel.
dataclassdataclassesGeneriert automatisch __init__, __repr__, __eq__ usw.
UserListcollectionsBasisklasse fĂŒr benutzerdefinierte Listen.
UserDictcollectionsBasisklasse fĂŒr benutzerdefinierte WörterbĂŒcher.

Andere sammlungsÀhnliche Typen

Obwohl nicht immer „Sammlungen“ genannt, reprĂ€sentieren oder speichern diese Typen ebenfalls Datengruppen.

1. str — Zeichenkette

Geordnete, unverÀnderbare Sequenz von Zeichen.

s = "Python"
print(len(s))        # → 6
print(s[0])          # → P
print('y' in s)      # → True
print(list(s))       # → ['P', 'y', 't', 'h', 'o', 'n']

2. bytes, bytearray

  • bytes — unverĂ€nderbare Byte-Sequenz.
  • bytearray — verĂ€nderbare Version.
b = b"hallo"
print(b[0])          # → 104
print(len(b))        # → 5

ba = bytearray(b"hallo")
ba[0] = 72
print(ba)            # → bytearray(b'Hallo')

3. range

Faule, geordnete Zahlenfolge. Speichert Elemente nicht im Speicher.

r = range(3)
print(list(r))       # → [0, 1, 2]
print(1 in r)        # → True
print(r[2])          # → 2

4. array.array

Speichert homogene numerische Daten kompakt (wie in C).

from array import array
arr = array('i', [1, 2, 3])  # 'i' = signed int
print(arr)                   # → array('i', [1, 2, 3])

5. Generatoren und Iteratoren

Speichern keine Daten — generieren sie bei Bedarf. UnterstĂŒtzen weder len() noch Indexierung.

gen = (x * 2 for x in range(3))
print(list(gen))     # → [0, 2, 4]
# len(gen) → TypeError

6. ChainMap (aus collections)

Gruppiert mehrere Dictionaries in einer einzigen Sicht — Suche durchlĂ€uft Maps in Reihenfolge.

from collections import ChainMap

d1 = {'a': 1}
d2 = {'b': 2}
cm = ChainMap(d1, d2)
print(cm['a'])       # → 1
print(cm['b'])       # → 2

7. OrderedDict (aus collections)

Dictionary, das EinfĂŒgereihenfolge beibehĂ€lt. Relevant fĂŒr Python < 3.7.

from collections import OrderedDict

od = OrderedDict([('a', 1), ('b', 2)])
print(od)            # → OrderedDict([('a', 1), ('b', 2)])

8. enum.Enum, enum.Flag

Sammlungen benannter Konstanten.

from enum import Enum

class Farbe(Enum):
    ROT = 1
    GRUEN = 2

print(list(Farbe))   # → [<Farbe.ROT: 1>, <Farbe.GRUEN: 2>]

9. typing.NamedTuple, typing.TypedDict

Typisierte Wrapper um namedtuple und dict.

from typing import NamedTuple, TypedDict

class Person(NamedTuple):
    name: str
    alter: int

p = Person("Anna", 25)

class Film(TypedDict):
    titel: str
    jahr: int

m: Film = {"titel": "Matrix", "jahr": 1999}

10. heapq, bisect — Werkzeuge, keine Sammlungen

Arbeiten mit Sammlungen, sind aber keine:

  • heapq — Heap-Warteschlange ĂŒber Listen.
  • bisect — hĂ€lt sortierte Reihenfolge in Listen.

1. Listen — list

Geordnete, verÀnderbare Sammlung. Elemente können sich wiederholen, beliebige Typen erlaubt.

Wird verwendet, wenn eine flexible Sequenz benötigt wird: HinzufĂŒgen, Entfernen, Ändern von Elementen.

Erstellung: []

lukas_list = ["Lukas", "Berlin", 30, "Ingenieur"]
print(f"Listen-Erstellung: {lukas_list}")
# → Listen-Erstellung: ['Lukas', 'Berlin', 30, 'Ingenieur']

print(f"Element bei Index 0: {lukas_list[0]}")
# → Element bei Index 0: Lukas

lukas_list[2] = 31
print(f"Nach Änderung: {lukas_list}")
# → Nach Änderung: ['Lukas', 'Berlin', 31, 'Ingenieur']

lukas_list.append("verheiratet")
print(f"Nach append: {lukas_list}")
# → Nach append: ['Lukas', 'Berlin', 31, 'Ingenieur', 'verheiratet']

lukas_list.insert(1, "Deutschland")
print(f"Nach insert: {lukas_list}")
# → Nach insert: ['Lukas', 'Deutschland', 'Berlin', 31, 'Ingenieur', 'verheiratet']

lukas_list.remove("Ingenieur")
print(f"Nach remove (Wert): {lukas_list}")
# → Nach remove (Wert): ['Lukas', 'Deutschland', 'Berlin', 31, 'verheiratet']

del lukas_list[2]
print(f"Nach Löschung (Index): {lukas_list}")
# → Nach Löschung (Index): ['Lukas', 'Deutschland', 31, 'verheiratet']

lukas_list.extend(["Hobbys", "Angeln"])
print(f"Nach extend: {lukas_list}")
# → Nach extend: ['Lukas', 'Deutschland', 31, 'verheiratet', 'Hobbys', 'Angeln']

lukas_list.pop()
print(f"Nach pop: {lukas_list}")
# → Nach pop: ['Lukas', 'Deutschland', 31, 'verheiratet', 'Hobbys']

2. WörterbĂŒcher — dict

Sammlung von SchlĂŒssel → Wert-Paaren. SchlĂŒssel mĂŒssen hashbar sein. Seit Python 3.7 bleibt die EinfĂŒgereihenfolge erhalten.

NĂŒtzlich fĂŒr strukturierte Daten: Profile, Konfigurationen, JSON.

Erstellung: {}

anna_dict = {"name": "Anna", "alter": 25, "stadt": "MĂŒnchen", "beruf": "KĂŒnstlerin"}
print(f"Dict-Erstellung: {anna_dict}")
# → Dict-Erstellung: {'name': 'Anna', 'alter': 25, 'stadt': 'MĂŒnchen', 'beruf': 'KĂŒnstlerin'}

print(f"Wert fĂŒr SchlĂŒssel 'name': {anna_dict['name']}")
# → Wert fĂŒr SchlĂŒssel 'name': Anna

anna_dict["alter"] = 26
print(f"Nach Aktualisierung: {anna_dict}")
# → Nach Aktualisierung: {'name': 'Anna', 'alter': 26, 'stadt': 'MĂŒnchen', 'beruf': 'KĂŒnstlerin'}

anna_dict["hobby"] = "Malerei"
print(f"Nach HinzufĂŒgen: {anna_dict}")
# → Nach HinzufĂŒgen: {'name': 'Anna', 'alter': 26, 'stadt': 'MĂŒnchen', 'beruf': 'KĂŒnstlerin', 'hobby': 'Malerei'}

del anna_dict["stadt"]
print(f"Nach Löschung: {anna_dict}")
# → Nach Löschung: {'name': 'Anna', 'alter': 26, 'beruf': 'KĂŒnstlerin', 'hobby': 'Malerei'}

hobby = anna_dict.pop("hobby")
print(f"Nach pop: {anna_dict}, Wert: {hobby}")
# → Nach pop: {'name': 'Anna', 'alter': 26, 'beruf': 'KĂŒnstlerin'}, Wert: Malerei

print(f"SchlĂŒssel 'name' vorhanden: {'name' in anna_dict}")
# → SchlĂŒssel 'name' vorhanden: True

3. Tupel — tuple

Geordnete, unverĂ€nderbare Sammlung. Geeignet fĂŒr feste Daten.

Wird verwendet, wenn UnverĂ€nderlichkeit wichtig ist: Koordinaten, Parameter, RĂŒckgabewerte.

Erstellung: ()

lukas_tuple = ("Lukas", "Berlin", 30, "Ingenieur")
print(f"Tupel-Erstellung: {lukas_tuple}")
# → Tupel-Erstellung: ('Lukas', 'Berlin', 30, 'Ingenieur')

print(f"Element bei Index 2: {lukas_tuple[2]}")
# → Element bei Index 2: 30

# lukas_tuple[0] = "Max"  → TypeError
# lukas_tuple.append("etwas") → AttributeError
  • Tupel verbrauchen weniger Speicher und sind schneller als Listen.
  • Ideal, wenn VerĂ€nderbarkeit nicht benötigt wird.

4. SimpleNamespace

Einfache Klasse aus types zur Erstellung von Objekten mit dynamischen Attributen. Zugriff per Punktnotation (obj.attr).

NĂŒtzlich, wenn man obj.name-Syntax ohne Klassendefinition möchte.

from types import SimpleNamespace

anna_ns = SimpleNamespace(name="Anna", alter=25, stadt="MĂŒnchen")
print(f"Objekt: {anna_ns}")
# → Objekt: namespace(name='Anna', alter=25, stadt='MĂŒnchen')

print(f"Name: {anna_ns.name}")
# → Name: Anna

anna_ns.alter = 26
print(f"Nach Änderung: {anna_ns}")
# → Nach Änderung: namespace(name='Anna', alter=26, stadt='MĂŒnchen')

anna_ns.beruf = "KĂŒnstlerin"
print(f"Mit neuem Attribut: {anna_ns}")
# → Mit neuem Attribut: namespace(name='Anna', alter=26, stadt='MĂŒnchen', beruf='KĂŒnstlerin')

del anna_ns.stadt
print(f"Nach Löschung: {anna_ns}")
# → Nach Löschung: namespace(name='Anna', alter=26, beruf='KĂŒnstlerin')

setattr(anna_ns, "hobby", "Malerei")
print(f"Via setattr: {anna_ns}")
# → Via setattr: namespace(name='Anna', alter=26, beruf='KĂŒnstlerin', hobby='Malerei')

delattr(anna_ns, "hobby")
print(f"Via delattr: {anna_ns}")
# → Via delattr: namespace(name='Anna', alter=26, beruf='KĂŒnstlerin')
  • Alternative zu dict, wenn obj.name gegenĂŒber obj['name'] bevorzugt wird.

5. Mengen — set

Ungeordnete Sammlung eindeutiger Elemente. UnterstĂŒtzt Mengenoperationen: Vereinigung, Schnitt, Differenz.

Wird zur Duplikatentfernung und MitgliedschaftsprĂŒfung verwendet.

Erstellung: {} oder set()

zahlen = {1, 2, 3, 3, 2, 1}
print(f"Menge: {zahlen}")
# → Menge: {1, 2, 3}

zahlen.add(4)
print(f"Nach HinzufĂŒgen: {zahlen}")
# → Nach HinzufĂŒgen: {1, 2, 3, 4}

zahlen.remove(2)
print(f"Nach Entfernen: {zahlen}")
# → Nach Entfernen: {1, 3, 4}

andere = {3, 4, 5}
print(f"Vereinigung: {zahlen | andere}")
# → Vereinigung: {1, 3, 4, 5}

print(f"Schnitt: {zahlen & andere}")
# → Schnitt: {3, 4}

print(f"Differenz: {zahlen - andere}")
# → Differenz: {1}

6. UnverĂ€nderbare Mengen — frozenset

UnverĂ€nderbare Version von set. Kann als Dictionary-SchlĂŒssel oder Mengenelement verwendet werden.

frozen = frozenset([1, 2, 3, 2])
print(f"frozenset: {frozen}")
# → frozenset: frozenset({1, 2, 3})

andere = frozenset([3, 4])
print(f"Schnitt: {frozen & andere}")
# → Schnitt: frozenset({3})

print(f"Vereinigung: {frozen | andere}")
# → Vereinigung: frozenset({1, 2, 3, 4})

# frozen.add(5) → AttributeError

7. namedtuple — benannte Tupel

UnverÀnderbare Struktur mit Zugriff per Feldname. Lesbarer als normale Tupel.

from collections import namedtuple

Person = namedtuple("Person", ["name", "alter", "stadt"])
anna = Person("Anna", 25, "MĂŒnchen")

print(f"Objekt: {anna}")
# → Objekt: Person(name='Anna', alter=25, stadt='MĂŒnchen')

print(f"Name: {anna.name}")
# → Name: Anna

print(f"Alter: {anna[1]}")
# → Alter: 25

# anna.alter = 26 → AttributeError

anna_neu = anna._replace(alter=26)
print(f"Kopie mit Änderung: {anna_neu}")
# → Kopie mit Änderung: Person(name='Anna', alter=26, stadt='MĂŒnchen')
  • Ideal fĂŒr DatensĂ€tze: Punkte, Benutzer, Konfigurationen — wenn UnverĂ€nderlichkeit und Lesbarkeit zĂ€hlen.

8. deque — doppelseitige Warteschlange

Optimiert fĂŒr schnelle Operationen an beiden Enden. Effizienter als list fĂŒr appendleft, popleft.

from collections import deque

d = deque([1, 2, 3])
print(f"Initiale deque: {d}")
# → Initiale deque: deque([1, 2, 3])

d.appendleft(0)
print(f"Nach appendleft: {d}")
# → Nach appendleft: deque([0, 1, 2, 3])

d.append(4)
print(f"Nach append: {d}")
# → Nach append: deque([0, 1, 2, 3, 4])

links = d.popleft()
print(f"Nach popleft: {links}, verbleibend: {d}")
# → Nach popleft: 0, verbleibend: deque([1, 2, 3, 4])

rechts = d.pop()
print(f"Nach pop: {rechts}, verbleibend: {d}")
# → Nach pop: 4, verbleibend: deque([1, 2, 3])
  • Wird in Algorithmen verwendet: BFS, LRU-Caches, Puffer — wenn Endoperationen schnell sein mĂŒssen.

9. Counter — ElementzĂ€hler

ZĂ€hlt die HĂ€ufigkeit von Elementen in einem iterierbaren Objekt. NĂŒtzlich fĂŒr Statistiken und Analysen.

from collections import Counter

text = "abracadabra"
c = Counter(text)
print(f"Buchstaben-ZĂ€hlung: {c}")
# → Buchstaben-ZĂ€hlung: Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})

print(f"HĂ€ufigkeit von 'a': {c['a']}")
# → HĂ€ufigkeit von 'a': 5

print(f"Top 3: {c.most_common(3)}")
# → Top 3: [('a', 5), ('b', 2), ('r', 2)]

c2 = Counter("bukva")
c.update(c2)
print(f"Nach update: {c}")
# → Nach update: Counter({'a': 6, 'b': 3, 'r': 2, 'c': 1, 'd': 1, 'u': 1, 'k': 1, 'v': 1})
  • NĂŒtzlich fĂŒr Textanalyse, Logs, Abstimmungen — ĂŒberall, wo „hĂ€ufigste Elemente“ zĂ€hlen.

10. defaultdict — Wörterbuch mit Standardwerten

Erzeugt automatisch Standardwerte fĂŒr fehlende SchlĂŒssel. Entfernt if key in dict-PrĂŒfungen.

from collections import defaultdict

dd_list = defaultdict(list)
dd_list["fruechte"].append("Apfel")
dd_list["fruechte"].append("Banane")
print(f"Liste: {dict(dd_list)}")
# → Liste: {'fruechte': ['Apfel', 'Banane']}

dd_int = defaultdict(int)
for char in "abracadabra":
    dd_int[char] += 1
print(f"ZĂ€hlungen: {dict(dd_int)}")
# → ZĂ€hlungen: {'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}

dd_set = defaultdict(set)
dd_set["staedte"].add("Berlin")
dd_set["staedte"].add("MĂŒnchen")
print(f"Menge: {dict(dd_set)}")
# → Menge: {'staedte': {'Berlin', 'MĂŒnchen'}}
  • Entfernt Boilerplate-Code wie if key not in d: d[key] = [].
  • Macht Code sauberer und sicherer.

11. dataclass — Datenklassen

Dekorator, der automatisch __init__, __repr__, __eq__ usw. generiert.

from dataclasses import dataclass

@dataclass
class Person:
    name: str
    alter: int
    stadt: str = "Nicht angegeben"

anna = Person("Anna", 25)
print(f"Objekt: {anna}")
# → Objekt: Person(name='Anna', alter=25, stadt='Nicht angegeben')

print(f"Name: {anna.name}")
# → Name: Anna

anna.alter = 26
print(f"Nach Änderung: {anna}")
# → Nach Änderung: Person(name='Anna', alter=26, stadt='Nicht angegeben')

bob = Person("Bob", 30)
print(f"Anna == Bob: {anna == bob}")
# → Anna == Bob: False

@dataclass(frozen=True)
class UnveraenderbarePerson:
    name: str
    alter: int

ivan = UnveraenderbarePerson("Ivan", 40)
# ivan.alter = 41 → FrozenInstanceError
  • Ersetzt manuelles Schreiben von __init__, __repr__, __eq__.
  • Ideal fĂŒr DTOs, Konfigurationen, Modelle.

12. UserList — benutzerdefinierte Listen

Erbt von collections.UserList. Wird verwendet, um Listen mit benutzerdefiniertem Verhalten zu erstellen.

from collections import UserList

class ProtokollierteListe(UserList):
    def append(self, item):
        print(f"[LOG] HinzufĂŒgen: {item}")
        super().append(item)

    def remove(self, item):
        print(f"[LOG] Entfernen: {item}")
        super().remove(item)

log_list = ProtokollierteListe([1, 2, 3])
print(f"Initial: {log_list}")
# → Initial: [1, 2, 3]

log_list.append(4)
# → [LOG] HinzufĂŒgen: 4
print(f"Nach append: {log_list}")
# → Nach append: [1, 2, 3, 4]

log_list.remove(2)
# → [LOG] Entfernen: 2
print(f"Nach remove: {log_list}")
# → Nach remove: [1, 3, 4]
  • NĂŒtzlich zum HinzufĂŒgen von Logging, Validierung oder zum Ändern des Standardlistenverhaltens.

13. UserDict — benutzerdefinierte WörterbĂŒcher

Erbt von collections.UserDict. Wird verwendet, um WörterbĂŒcher mit benutzerdefiniertem Verhalten zu erstellen.

from collections import UserDict

class KleinschreibDict(UserDict):
    def __setitem__(self, key, value):
        key = key.lower() if isinstance(key, str) else key
        super().__setitem__(key, value)

    def __getitem__(self, key):
        key = key.lower() if isinstance(key, str) else key
        return super().__getitem__(key)

ld = KleinschreibDict()
ld["Name"] = "Anna"
print(f"Wert fĂŒr 'Name': {ld['Name']}")
# → Wert fĂŒr 'Name': Anna
print(f"Wert fĂŒr 'name': {ld['name']}")
# → Wert fĂŒr 'name': Anna
print(f"SchlĂŒssel: {list(ld.keys())}")
# → SchlĂŒssel: ['name']
  • Wird zur SchlĂŒsselnormalisierung, Validierung, Protokollierung, Caching usw. verwendet.

📈 Speicher- und Leistungsvergleich

Die Wahl der Sammlung beeinflusst Leistung und Speicherverbrauch. Hier praktische Benchmarks.


1. Speicher: list vs tuple vs array.array

import sys
from array import array

n = 1_000_000
data = list(range(n))
data_t = tuple(range(n))
data_a = array('i', range(n))

print(f"list:  {sys.getsizeof(data) / 1024 / 1024:.2f} MB")
# → list:  8.00 MB

print(f"tuple: {sys.getsizeof(data_t) / 1024 / 1024:.2f} MB")
# → tuple: 8.00 MB

print(f"array: {sys.getsizeof(data_a) / 1024 / 1024:.2f} MB")
# → array: 3.81 MB
  • array.array verbraucht ~2x weniger Speicher fĂŒr Zahlen.
  • list und tuple verbrauchen Ă€hnlichen Speicher, aber tuple ist etwas schneller bei Iteration.

2. Zugriffsgeschwindigkeit: list vs tuple vs array.array

import time

def time_access(collection, name):
    start = time.perf_counter()
    total = 0
    for i in range(len(collection)):
        total += collection[i]
    end = time.perf_counter()
    print(f"{name}: {end - start:.4f} Sekunden")

n = 10_000_000
lst = list(range(n))
tpl = tuple(range(n))
arr = array('i', range(n))

time_access(lst, "list")   # → list: 1.2000 Sekunden
time_access(tpl, "tuple")  # → tuple: 1.0000 Sekunden
time_access(arr, "array")  # → array: 0.8000 Sekunden
  • array.array ist am schnellsten fĂŒr numerische Daten.
  • tuple ist 10–20% schneller als list.
  • Unterschied bemerkbar bei großen Datenmengen.

3. Speicher: dict vs SimpleNamespace vs dataclass

d = {"name": "A", "alter": 25, "stadt": "X", "hobby": "Y", "job": "Z"}
ns = SimpleNamespace(name="A", alter=25, stadt="X", hobby="Y", job="Z")
dc = PersonDC("A", 25, "X", "Y", "Z")

print(f"dict:      {sys.getsizeof(d)} Bytes")          # → 232
print(f"SimpleNamespace: {sys.getsizeof(ns)} Bytes")   # → 64
print(f"dataclass: {sys.getsizeof(dc)} Bytes")         # → 64
print(f"ns.__dict__: {sys.getsizeof(ns.__dict__)} Bytes")  # → 232
  • SimpleNamespace und dataclass verbrauchen so viel Speicher wie dict wegen __dict__.
  • Verwenden Sie __slots__ zur Speicherersparnis.

4. Speicheroptimierung: dataclass mit __slots__

@dataclass
class PersonSlots:
    __slots__ = ("name", "alter", "stadt", "hobby", "job")
    name: str
    alter: int
    stadt: str
    hobby: str
    job: str

dc_slots = PersonSlots("A", 25, "X", "Y", "Z")
print(f"dataclass + slots: {sys.getsizeof(dc_slots)} Bytes")
# → 80 Bytes

# dc_slots.neu = "Wert" → AttributeError
  • __slots__ spart Speicher und beschleunigt Attributzugriff.
  • Nachteil: keine dynamischen Attribute.

5. Suchgeschwindigkeit: list vs set

n = 1_000_000
lst = list(range(n))
st = set(range(n))

def time_in(collection, target, name):
    start = time.perf_counter()
    for _ in range(1000):
        _ = target in collection
    end = time.perf_counter()
    print(f"{name} (Suche {target}): {end - start:.4f} Sekunden")

time_in(lst, 999_999, "list")   # → 10.0000 Sekunden
time_in(st, 999_999, "set")     # → 0.0005 Sekunden
  • set ist tausendmal schneller als list fĂŒr MitgliedschaftsprĂŒfungen.
  • Immer set verwenden, wenn hĂ€ufig x in collection geprĂŒft wird.

6. Speicher: set vs frozenset

s = set(range(1000))
fs = frozenset(range(1000))

print(f"set:       {sys.getsizeof(s)} Bytes")     # → 32792
print(f"frozenset: {sys.getsizeof(fs)} Bytes")   # → 32792
  • frozenset und set verbrauchen identischen Speicher.
  • Unterschied nur in der VerĂ€nderbarkeit.

7. HinzufĂŒgungsgeschwindigkeit: list.append vs deque.append vs deque.appendleft

from collections import deque
import time

def time_append(collection, n, method='append'):
    start = time.perf_counter()
    for i in range(n):
        if method == 'appendleft' and hasattr(collection, 'appendleft'):
            collection.appendleft(i)
        else:
            collection.append(i)
    end = time.perf_counter()
    return end - start

n = 100_000

lst = []
dq = deque()

time_list_append = time_append(lst, n)              # → 0.0100 Sekunden
time_deque_append = time_append(dq, n)              # → 0.0100 Sekunden
time_deque_appendleft = time_append(deque(), n, 'appendleft')  # → 0.0100 Sekunden

# list.insert(0):
lst = []
start = time.perf_counter()
for i in range(n):
    lst.insert(0, i)
end = time.perf_counter()
print(f"list.insert(0):   {end - start:.4f} Sekunden")   # → 5.0000 Sekunden
  • deque.appendleft ist O(1), im Gegensatz zu list.insert(0) (O(n)).
  • Verwenden Sie deque fĂŒr hĂ€ufige Operationen an beiden Enden.

🧠 Leistungsempfehlungen

SituationVerwendenGrund
Zahlen speichern, Speicher kritischarray.array2x weniger Speicher, schneller Zugriff
UnverÀnderliche DatentupleSchneller als list, sicherer
HĂ€ufige x in collection-PrĂŒfungenset / frozensetO(1) vs O(n) von list
Operationen an beiden Endendequeappendleft/popleft in O(1)
Strukturierte Daten, Speicher kritischdataclass + __slots__Kein __dict__, weniger Speicher
HĂ€ufigkeiten zĂ€hlenCounterFĂŒr diese Aufgabe optimiert
Benutzerdefiniertes VerhaltenUserList / UserDictSichere Erweiterung integrierter Sammlungen

📊 Sammlungsvergleich

TypGeordnetVerÀnderbarEindeutige ElementeIndexzugriffDuplikate
list✅ Ja✅ Ja❌ Nein✅ Ja✅ Ja
tuple✅ Ja❌ Nein❌ Nein✅ Ja✅ Ja
dict✅ Ja*✅ JaNur SchlĂŒssel❌ NeinWerte: ✅
set❌ Nein✅ Ja✅ Ja❌ Nein❌ Nein
frozenset❌ Nein❌ Nein✅ Ja❌ Nein❌ Nein
SimpleNamespace✅ Ja (Attrs)✅ Ja❌ Nein (Attrs können semantisch doppelt sein)❌ Nein✅ Ja
namedtuple✅ Ja❌ Nein❌ Nein✅ Ja✅ Ja
deque✅ Ja✅ Ja❌ Nein✅ Ja✅ Ja
Counter❌ Nein✅ Ja❌ Nein❌ Nein (aber hat SchlĂŒssel)✅ Ja
defaultdict✅ Ja*✅ JaNur SchlĂŒssel❌ NeinWerte: ✅
dataclass✅ Ja (Felder)✅ Ja (wenn nicht frozen)❌ Nein❌ Nein✅ Ja
UserList✅ Ja✅ Ja❌ Nein✅ Ja✅ Ja
UserDict✅ Ja*✅ JaNur SchlĂŒssel❌ NeinWerte: ✅
str✅ Ja❌ Nein❌ Nein✅ Ja✅ Ja
bytes✅ Ja❌ Nein❌ Nein✅ Ja✅ Ja
bytearray✅ Ja✅ Ja❌ Nein✅ Ja✅ Ja
range✅ Ja❌ Nein❌ Nein✅ Ja❌ Nein
array.array✅ Ja✅ Ja❌ Nein✅ Ja✅ Ja
ChainMap✅ Ja*✅ JaNur SchlĂŒssel❌ NeinWerte: ✅
Enum✅ Ja❌ Nein✅ Ja (Mitglieder)❌ Nein❌ Nein
  • — seit Python 3.7 behalten dict, defaultdict, UserDict, ChainMap EinfĂŒgereihenfolge bei.

💡 Wann was verwenden?

AufgabeSammlung
VerÀnderbare Sequenzlist / deque / UserList / bytearray
UnverÀnderliche Datentuple / namedtuple / frozenset / str / bytes
Schnelle Suche, Duplikate entfernenset / frozenset
Strukturierte Datendict / dataclass / SimpleNamespace / UserDict / TypedDict
Als Dictionary-SchlĂŒssel verwendbarfrozenset
TemporÀre Objekte mit PunktzugriffSimpleNamespace / dataclass
HÀufigkeiten zÀhlenCounter
Standardwerte fĂŒr SchlĂŒsseldefaultdict
Effiziente Endoperationendeque
Benutzerdefiniertes ListenverhaltenUserList
Benutzerdefiniertes Dict-VerhaltenUserDict
BinÀrdatenbytes / bytearray / array.array
Konfigurationen mit HierarchieChainMap
Benannte KonstantenEnum
Faule Sequenzenrange / Generatoren

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert