Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Datenstrukturen (Collections)

1 Listen

1.1 Zugriff auf Elemente, Teillisten

L = ['Null', 'Eins', 'Zwei', 'Drei']

# Anzahl der Elemente
print(len(L))  # 4

# Element 1
print(L[1])    # Eins

# Element 0-2
print(L[0:2])  # ['Null', 'Eins']

# Die letzten beiden Elemente
print(L[-2:])  # ['Zwei', 'Drei']

1.2 Elemente hinzufügen und löschen

L = [2, 4, 6, 8]
L.append(10)  # Der Wert 10 wird hinzugefügt
print(L)      # [2, 4, 6, 8, 10]

L.remove(4)   # Der Wert 4 wird entfernt (NICHT Element 4)
print(L)      # [2, 6, 8, 10]

del L[0:2]    # Element 0-1 werden gelöscht, kein Rückgabewert
print(L)      # [8, 10]

del L[1]      # Element 1 wird gelöscht, kein Rückgabewert
print(L)      # [8]

# Element 0 wird entfernt und zurückgegeben
print(L.pop(0))  # 8

1.3 Listen kombinieren

L1 = [1, 2, 3]
L2 = [4, 5, 6]

# Möglichkeit 1
print(L1 + L2)  # [1, 2, 3, 4, 5, 6]

L1.extend(L2)

# Möglichkeit 2
print(L1)       # [1, 2, 3, 4, 5, 6]

Prüfen, ob Wert in Liste ist:

L = ['A', 'B', 'C']
x = 'B'
print(x in L)  # True

1.4 List comprehensions (kompakte Erstellung von Listen)

Eine List Comprehension ist eine kompakte Schreibweise zur Erstellung von Listen. Sie fasst eine for-Schleife – optional mit einer if-Bedingung – in einem einzigen Ausdruck zusammen.

Syntax:

[ausdruck for element in iterable]
[ausdruck for element in iterable if bedingung]

Beispiel 1:

numbers = []
for i in range(5):
    numbers.append(i**2)
print(numbers)  # [0, 1, 4, 9, 16]

# List comprehension:
numbers = [i**2 for i in range(5)]
print(numbers)  # [0, 1, 4, 9, 16]

Beispiel 2:

L2 = []
for i in range(0, len(L)):
    if L[i] > 1:
        L2.append(L[i]*2)
print(L2)                         # [4, 6]

# List comprehension:
L = [1, 2, 3]
print([x*2 for x in L if x > 1])  # [4, 6]

1.4.1 Lesbarkeit von List Comprehensions

List Comprehensions sind in manchen Fällen besser lesbar, können jedoch auch schnell unübersichtlich werden!

Beispiel 1 (List Comprehension ist besser lesbar):

# Besser als List Comprehension – kompakt und klar:
squares = [x**2 for x in range(10)]

# Normale Schreibweise (umständlicher):
squares = []
for x in range(10):
    squares.append(x**2)

Beispiel 2 (Normale Schreibweise ist verständlicher):

# Normale Schreibweise – übersichtlicher bei komplexer Logik:
results = []
for x in range(10):
    value = x ** 2
    if value % 3 == 0 and value > 5:
        results.append(value * 2 - 1)

# List Comprehension (schwerer lesbar):
results = [x**2 * 2 - 1 for x in range(10) if x**2 % 3 == 0 and x**2 > 5]

Tip

Sobald die List Comprehension nicht mehr in eine einzelne Zeile passt oder mehrere verschachtelte Bedingungen enthält, ist die normale Schreibweise vorzuziehen.

1.4.2 List comprehensions mit if-Bedingungen

Beispiel 1:

# Beispiel 1
numbers = [i*-1 if i<3 else -1 for i in range(5)]
print(numbers)  # [0, -1, -2, -1, -1]

# Beispiel 2
numbers = [i+1 for i in range(5) if i != 3]
print(numbers)  # [1, 2, 3, 5]

Beim ersten Beispiel steht die if-Bedingung am Anfang, dadurch wird festgelegt, was abgespeichert wird. Beim zweiten Beispiel, bei der die if-Bedingung am Ende steht, wird festgelegt, ob überhaupt etwas abgespeichert werden soll.

1.5 Kopieren von Listen

danger

Das Kopieren einer Liste über Variablenzuweisen (z. B. l2 = l1) führt häufig zu einem nicht gewollten Verhalten, da das Ändern von l2 auch die Änderung von l1 mit sich bringt.

Beispiel:

l1 = [1, 2]
l2 = l1
l2[0] = 3
print(l1)  # [3, 2]
print(l2)  # [3, 2]

Dies liegt daran, dass auf diese Weite l1 und l2 auf dieselbe Speicheradresse verweisen:

l1 = [1, 2]
l2 = l1
print(id(l1))  # 1957190476864
print(id(l2))  # 1957190476864

Um das zu umgehen, kopiert man Listen wie folgt:

l1 = [1, 2]
l2 = l1.copy()
l2[0] = 3
print(l1)  # [1, 2]
print(l2)  # [3, 2]

warning

Dies ist eine sog. shallow-copy. Bei mehrdimensionalen Listen funktioniert dies jedoch nicht! Es muss eine sog. deep-copy erstellt werden.

Beispiel für shallow-copy:

import copy

l1 = [[1, 2], [3, 4]]
l2 = l1.copy()  # oder l2 = copy.copy(l1)
l2[0][0] = 5
print(l1)  # [[5, 2], [3, 4]]
print(l2)  # [[5, 2], [3, 4]]
print(id(l1))        # 1957176932224
print(id(l2))        # 1957176994368
print(id(l1[0][0]))  # 1956557750640
print(id(l2[0][0]))  # 1956557750640

Beispiel für deep-copy:

import copy

l1 = [[1, 2], [3, 4]]
l2 = copy.deepcopy(l1)
l2[0][0] = 5
print(l1)            # [[1, 2], [3, 4]]
print(l2)            # [[5, 2], [3, 4]]
print(id(l1))        # 1957190472320
print(id(l2))        # 1957190477184
print(id(l1[0][0]))  # 1956557750512
print(id(l2[0][0]))  # 1956557750640

2 Arrays

Arrays sind ähnlich wie Listen, jedoch effizienter bei numerischen Operationen, insbesondere für große Datenmengen. In Python können Arrays mit dem array-Modul oder über NumPy verwendet werden.

import array

# Ein Array mit ganzen Zahlen (Typcode 'i' für Integer)
arr = array.array('i', [1, 2, 3, 4, 5])
print(arr)  # array('i', [1, 2, 3, 4, 5])

# Elementzugriff
print(arr[1])  # 2

# Element hinzufügen
arr.append(6)
print(arr)  # array('i', [1, 2, 3, 4, 5, 6])

# Element entfernen
arr.remove(3)
print(arr)  # array('i', [1, 2, 4, 5, 6])

3 Tupel

Tupel sind wie Listen, jedoch mit dem Unterschied, dass der Inhalt des Tupels nicht veränderbar ist.

t = 1, 2, 3
t = (1, 2, 3)
print(t[0])  # 1

3.1 Tuple unpacking

Beim Tuple Unpacking werden die Elemente eines Tupels in einem einzigen Schritt mehreren Variablen zugewiesen. Mit _ als Platzhalter ignoriert man einzelne Werte, mit * fasst man mehrere verbleibende Elemente in einer Liste zusammen.

t = (1, 2, 3)

val1, val2, val3 = t
print(val1, val2, val3)  # 1 2 3

val1, _, val3 = t
print(val1, val3)        # 1 3

val1, *t2 = t
print(val1, t2)          # 1 [2, 3]

4 Dictionaries

Dictionaries werden benutzt, um Daten in key-value-Paaren zu speichern.

Erstellung von Dictionaries:

# Möglichkeit 1:
year = {'Ford': 2019, 'Honda': 2013}
print(year)  # {'Ford': 2019, 'Honda': 2013}

# Möglichkeit 2:
year = dict(Ford = 2019, Honda = 2013)
print(year)  # {'Ford': 2019, 'Honda': 2013}

# Möglichkeit 3: Schlüssel werden als Tupel übergeben)
year = dict.fromkeys( ('Ford', 'Honda') )
year['Ford'] = 2019
year['Honda'] = 2013
print(year)  # {'Ford': 2019, 'Honda': 2013}

Zugriff auf die Schlüssel und Werte von Dictionaries in Schleifen:

D = {'Ford': 2019, 'Honda': 2013}

print('Schlüssel des Dictionaries:')
for key in D:
    print(key)
    # Ford
    # Honda

print('\nWerte des Dictionaries:')
for value in D.values():
    print(value)
    # 2019
    # 2013

print('\nSchlüssel und Werte des Dictionaries:')
for key, value in D.items():
    print(f'{key}: {value}')
    # Ford: 2019
    # Honda: 2013

note

Seit Python 3.7 ist die Einfügereihenfolge von Dictionaries garantiert. In älteren Python-Versionen war die Reihenfolge der Schlüssel nicht definiert.

5 Sets bzw. Mengen

Siehe auch operatoren.

Operationen:

S1 = {'Banane', 'Paprika', 'Zitrone'}
S2 = {'Apfel', 'Banane', 'Birne', 'Gurke', 'Paprika'}

# Vereinigung
print(S1 | S2)  # {'Zitrone', 'Gurke', 'Birne', 'Paprika', 'Apfel', 'Banane'}

# Schnittmenge
print(S1 & S2)  # {'Paprika', 'Banane'}

# Differenz (S1 ohne S2)
print(S1 - S2)  # {'Zitrone'}

# Symmetrische Differenz (= Vereinigung ohne Schnittmenge)
print(S1 ^ S2)  # {'Apfel', 'Zitrone', 'Gurke', 'Birne'}

print('\nAlternativen:')

# Vereinigung
print(S1.union(S2)) # {'Zitrone', 'Gurke', 'Birne', 'Paprika', 'Apfel', 'Banane'}

# Schnittmenge
print(S1.intersection(S2))  # {'Paprika', 'Banane'}

# Differenz (S1 ohne S2)
print(S1.difference(S2))    # {'Zitrone'}

# Symmetrische Differenz (= Vereinigung ohne Schnittmenge)
print(S1.symmetric_difference(S2))  # {'Apfel', 'Zitrone', 'Gurke', 'Birne'}

Mehr zu Datentypen: https://docs.python.org/3/library/stdtypes.html

6 Das collections-Modul

Die eingebauten Datenstrukturen list, dict, tuple und set decken die meisten Anwendungsfälle ab. Das collections-Modul ergänzt sie um spezialisierte Container, die für bestimmte Aufgaben effizienter oder ausdrucksstärker sind und häufig wiederkehrenden Boilerplate-Code vermeiden.

6.1 Counter – Zählen von Elementen

Counter ist ein Dictionary-Subtyp zum Zählen von hashbaren Objekten.

6.1.1 Grundlegende Verwendung

from collections import Counter

# Aus Liste erstellen
words = ['Apfel', 'Banane', 'Apfel', 'Tomate', 'Banane', 'Apfel']
counter = Counter(words)
print(counter)  # Counter({'Apfel': 3, 'Banane': 2, 'Tomate': 1})

# Aus String erstellen (zählt Zeichen)
text = 'mississippi'
counter = Counter(text)
print(counter)  # Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})

# Direkte Initialisierung
counter = Counter(a=3, b=2, c=1)
print(counter)  # Counter({'a': 3, 'b': 2, 'c': 1})

6.1.2 Häufigste Elemente

from collections import Counter

votes = ['Anna', 'Bernd', 'Anna', 'Christian', 'Bernd', 'Anna']
counter = Counter(votes)

# Häufigste n Elemente
print(counter.most_common(2))  # [('Anna', 3), ('Bernd', 2)]

# Alle Elemente nach Häufigkeit
print(counter.most_common())   # [('Anna', 3), ('Bernd', 2), ('Christian', 1)]

6.1.3 Counter-Operationen

from collections import Counter

c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)

# Addition
print(c1 + c2)  # Counter({'a': 4, 'b': 3})

# Subtraktion (negative Werte werden entfernt)
print(c1 - c2)  # Counter({'a': 2})

# Vereinigung (Maximum)
print(c1 | c2)  # Counter({'a': 3, 'b': 2})

# Schnittmenge (Minimum)
print(c1 & c2)  # Counter({'a': 1, 'b': 1})

6.1.4 Praktische Beispiele

Wortfrequenz-Analyse:

from collections import Counter

text = """Python ist eine wunderbare Programmiersprache. 
Python macht Spaß und Python ist mächtig."""

words = text.lower().split()
word_count = Counter(words)

print(word_count.most_common(3))
# [('python', 3), ('ist', 2), ('eine', 1)]

Duplikate finden:

from collections import Counter

data = [1, 2, 3, 2, 4, 5, 3, 6, 7, 3]
counter = Counter(data)

# Elemente, die mehr als einmal vorkommen
duplicates = [item for item, count in counter.items() if count > 1]
print(duplicates)  # [2, 3]

6.2 defaultdict – Dictionary mit Standardwerten

defaultdict erstellt automatisch Standardwerte für fehlende Schlüssel.

6.2.1 Grundkonzept

from collections import defaultdict

# Mit list als Factory
d = defaultdict(list)
d['obst'].append('Apfel')
d['obst'].append('Banane')
d['gemüse'].append('Karotte')

print(d)  # defaultdict(<class 'list'>, {'obst': ['Apfel', 'Banane'], 'gemüse': ['Karotte']})

# Mit int als Factory (Standardwert 0)
counter = defaultdict(int)
for word in ['a', 'b', 'a', 'c', 'b', 'a']:
    counter[word] += 1

print(counter)  # defaultdict(<class 'int'>, {'a': 3, 'b': 2, 'c': 1})

6.2.2 Verschiedene Factory-Funktionen

from collections import defaultdict

# list - leere Liste
d1 = defaultdict(list)
print(d1['key'])  # []

# int - 0
d2 = defaultdict(int)
print(d2['key'])  # 0

# str - leerer String
d3 = defaultdict(str)
print(d3['key'])  # ''

# set - leeres Set
d4 = defaultdict(set)
print(d4['key'])  # set()

# Lambda für custom Defaults
d5 = defaultdict(lambda: 'N/A')
print(d5['key'])  # 'N/A'

6.2.3 Vergleich: dict vs. defaultdict

# Normales dict
d = {}
d['key'].append('value')  # KeyError!

# Mit setdefault (umständlich)
d.setdefault('key', []).append('value')

# Mit defaultdict (elegant)
from collections import defaultdict
d = defaultdict(list)
d['key'].append('value')  # Funktioniert!

6.2.4 Praktische Beispiele

Gruppieren nach Schlüssel:

from collections import defaultdict

students = [
    ('Anna', 'Mathe'),
    ('Bernd', 'Physik'),
    ('Christian', 'Mathe'),
    ('David', 'Physik'),
    ('Erwin', 'Mathe')
]

by_subject = defaultdict(list)
for name, subject in students:
    by_subject[subject].append(name)

print(dict(by_subject))
# {'Mathe': ['Anna', 'Christian', 'Erwin'], 'Physik': ['Bernd', 'David']}

Verschachtelte defaultdict:

from collections import defaultdict

# Zweistufiges defaultdict
tree = lambda: defaultdict(tree)
users = tree()

users['Bernd']['age'] = 30
users['Bernd']['city'] = 'New York'
users['Anna']['age'] = 25

print(dict(users))
# {'Bernd': {'age': 30, 'city': 'New York'}, 'Anna': {'age': 25}}

6.3 deque – Double-Ended Queue

Im Gegensatz zur normalen Liste, bei der das Einfügen oder Entfernen am Anfang alle übrigen Elemente verschiebt (O(n)), bietet deque für beide Enden konstante Zeit (O(1)). Sie eignet sich daher besonders für Queues, Stacks und Sliding-Window-Algorithmen, bei denen häufig Elemente vorne oder hinten eingefügt bzw. entfernt werden.

6.3.1 Grundoperationen

from collections import deque

# Erstellen
d = deque([1, 2, 3])
print(d)  # deque([1, 2, 3])

# Am Ende hinzufügen/entfernen (wie Liste)
d.append(4)
print(d)  # deque([1, 2, 3, 4])

last = d.pop()
print(last, d)  # 4 deque([1, 2, 3])

# Am Anfang hinzufügen/entfernen (O(1) statt O(n))
d.appendleft(0)
print(d)  # deque([0, 1, 2, 3])

first = d.popleft()
print(first, d)  # 0 deque([1, 2, 3])

6.3.2 Rotation und Erweiterung

from collections import deque

d = deque([1, 2, 3, 4, 5])

# Rotation nach rechts
d.rotate(2)
print(d)  # deque([4, 5, 1, 2, 3])

# Rotation nach links
d.rotate(-2)
print(d)  # deque([1, 2, 3, 4, 5])

# Mehrere Elemente hinzufügen
d.extend([6, 7])
print(d)  # deque([1, 2, 3, 4, 5, 6, 7])

d.extendleft([0, -1])
print(d)  # deque([-1, 0, 1, 2, 3, 4, 5, 6, 7])

6.3.3 Maximale Länge (Ringbuffer)

from collections import deque

# Deque mit maximaler Länge
d = deque(maxlen=3)

d.append(1)
d.append(2)
d.append(3)
print(d)     # deque([1, 2, 3], maxlen=3)

d.append(4)  # Ältestes Element (1) wird automatisch entfernt
print(d)     # deque([2, 3, 4], maxlen=3)

6.3.4 Performance-Vergleich: list vs. deque

from collections import deque
import time

# Liste
data_list = []
start = time.time()
for i in range(100000):
    data_list.insert(0, i)  # O(n) - langsam!
print(f'List insert(0): {time.time() - start:.3f}s')

# Deque
data_deque = deque()
start = time.time()
for i in range(100000):
    data_deque.appendleft(i)  # O(1) - schnell!
print(f'Deque appendleft: {time.time() - start:.3f}s')

Typisches Ergebnis:

  • List insert(0): 3.5 s
  • Deque appendleft: 0.01 s

6.3.5 Praktische Beispiele

FIFO-Queue (First In, First Out):

from collections import deque

queue = deque()

# Elemente hinzufügen
queue.append('Aufgabe 1')
queue.append('Aufgabe 2')
queue.append('Aufgabe 3')

# Elemente verarbeiten (FIFO)
while queue:
    task = queue.popleft()
    print(f'Verarbeite: {task}')

Sliding Window:

from collections import deque

def moving_average(values, window_size):
    """Berechnet gleitenden Durchschnitt"""
    window = deque(maxlen=window_size)
    averages = []
    
    for value in values:
        window.append(value)
        averages.append(sum(window) / len(window))
    
    return averages

data = [10, 20, 30, 40, 50, 60]
result = moving_average(data, window_size=3)
print(result)  # [10.0, 15.0, 20.0, 30.0, 40.0, 50.0]

**Browser History (Back/Forward): **

from collections import deque

class BrowserHistory:
    def __init__(self):
        self.back_stack = deque()
        self.forward_stack = deque()
        self.current = None
    
    def visit(self, url):
        if self.current:
            self.back_stack.append(self.current)
        self.current = url
        self.forward_stack.clear()
    
    def back(self):
        if self.back_stack:
            self.forward_stack.append(self.current)
            self.current = self.back_stack.pop()
        return self.current
    
    def forward(self):
        if self.forward_stack:
            self.back_stack.append(self.current)
            self.current = self.forward_stack.pop()
        return self.current

# Verwendung
browser = BrowserHistory()
browser.visit('google.com')
browser.visit('python.org')
browser.visit('github.com')
print(browser.back())     # python.org
print(browser.back())     # google.com
print(browser.forward())  # python.org

6.4 ChainMap – Mehrere Dictionaries verketten

ChainMap gruppiert mehrere Dictionaries zu einem einzigen View.

6.4.1 Grundkonzept

from collections import ChainMap

dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
dict3 = {'c': 5, 'd': 6}

# ChainMap erstellen
chain = ChainMap(dict1, dict2, dict3)

print(chain['a'])  # 1 (aus dict1)
print(chain['b'])  # 2 (aus dict1, nicht dict2!)
print(chain['c'])  # 4 (aus dict2, nicht dict3!)
print(chain['d'])  # 6 (aus dict3)

important

Bei Lookup wird das erste Dictionary mit dem Schlüssel verwendet.

6.4.2 Modifikationen

from collections import ChainMap

user_config = {'theme': 'dark', 'font_size': 12}
default_config = {'theme': 'light', 'font_size': 14, 'auto_save': True}

config = ChainMap(user_config, default_config)

print(config['theme'])      # 'dark' (aus user_config)
print(config['auto_save'])  # True (aus default_config)

# Änderungen gehen ins ERSTE Dictionary
config['theme'] = 'blue'
print(user_config)     # {'theme': 'blue', 'font_size': 12}
print(default_config)  # Unverändert

# Neuer Schlüssel wird auch ins ERSTE Dictionary eingefügt
config['new_key'] = 'value'
print(user_config)  # {'theme': 'blue', 'font_size': 12, 'new_key': 'value'}

6.4.3 Methoden

from collections import ChainMap

dict1 = {'a': 1}
dict2 = {'b': 2}

chain = ChainMap(dict1, dict2)

# Neues Dictionary vorne hinzufügen
chain = chain.new_child({'c': 3})
print(chain)  # ChainMap({'c': 3}, {'a': 1}, {'b': 2})

# Erstes Dictionary entfernen
chain = chain.parents
print(chain)  # ChainMap({'a': 1}, {'b': 2})

# Alle Maps anzeigen
print(chain.maps)  # [{'a': 1}, {'b': 2}]

6.4.4 Praktische Beispiele

Konfiguration mit Fallbacks:

from collections import ChainMap
import os

# Priorität: CLI-Args > Env-Vars > Config-File > Defaults
defaults = {
    'host': 'localhost',
    'port': 8000,
    'debug': False
}

config_file = {
    'host': '0.0.0.0',
    'port': 3000
}

env_vars = {
    k.lower().replace('app_', ''): v 
    for k, v in os.environ.items() 
    if k.startswith('APP_')
}

cli_args = {
    'debug': True
}

config = ChainMap(cli_args, env_vars, config_file, defaults)

print(config['host'])   # '0.0.0.0' (aus config_file)
print(config['debug'])  # True (aus cli_args)
print(config['port'])   # 3000 (aus config_file)

Scope-Management (z.B. für Interpreter):

from collections import ChainMap

class Scope:
    def __init__(self):
        self.scopes = ChainMap({})
    
    def push_scope(self):
        """Neuer Scope (z.B. neue Funktion)"""
        self.scopes = self.scopes.new_child()
    
    def pop_scope(self):
        """Scope verlassen"""
        self.scopes = self.scopes.parents
    
    def set(self, name, value):
        """Variable im aktuellen Scope setzen"""
        self.scopes[name] = value
    
    def get(self, name):
        """Variable nachschlagen (mit Fallback zu äußeren Scopes)"""
        return self.scopes.get(name)

# Verwendung
scope = Scope()
scope.set('x', 10)     # Global: x=10

scope.push_scope()     # Neue Funktion
scope.set('x', 20)     # Lokal: x=20
print(scope.get('x'))  # 20

scope.pop_scope()      # Funktion verlassen
print(scope.get('x'))  # 10 (global wieder sichtbar)

6.5 namedtuple – Tupel mit benannten Feldern

namedtuple erstellt Tuple-Subklassen mit benannten Feldern.

6.5.1 Grundlegende Verwendung

from collections import namedtuple

# namedtuple-Klasse definieren
Point = namedtuple('Point', ['x', 'y'])

# Instanzen erstellen
p1 = Point(10, 20)
p2 = Point(x=30, y=40)

# Zugriff per Name oder Index
print(p1.x)   # 10
print(p1[0])  # 10
print(p1.y)   # 20

# Tuple unpacking funktioniert
x, y = p1
print(x, y)   # 10 20

6.5.2 Verschiedene Erstellungsmethoden

from collections import namedtuple

# Methode 1: Liste von Strings
Point = namedtuple('Point', ['x', 'y'])

# Methode 2: String mit Leerzeichen
Point = namedtuple('Point', 'x y')

# Methode 3: String mit Kommas
Point = namedtuple('Point', 'x, y')

6.5.3 Methoden von namedtuple

from collections import namedtuple

Point = namedtuple('Point', 'x y')
p = Point(10, 20)

# Als Dictionary
print(p._asdict())  # {'x': 10, 'y': 20}

# Felder anzeigen
print(p._fields)    # ('x', 'y')

# Neues Objekt mit geänderten Werten
p2 = p._replace(x=30)
print(p2)           # Point(x=30, y=20)

# Aus iterable erstellen
Point._make([40, 50])  # Point(x=40, y=50)

6.5.4 Default-Werte

from collections import namedtuple

# Mit defaults (Python 3.7+)
Point = namedtuple('Point', ['x', 'y', 'z'], defaults=[0, 0, 0])

p1 = Point()
print(p1)  # Point(x=0, y=0, z=0)

p2 = Point(10)
print(p2)  # Point(x=10, y=0, z=0)

p3 = Point(10, 20)
print(p3)  # Point(x=10, y=20, z=0)

6.5.5 Vergleich: namedtuple vs. dict vs. class

from collections import namedtuple

# namedtuple
Person = namedtuple('Person', 'name age')
p1 = Person('Anna', 30)

# Dictionary
p2 = {'name': 'Anna', 'age': 30}

# Klasse
class PersonClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age
p3 = PersonClass('Anna', 30)

# Speicherverbrauch
import sys
print(f'namedtuple: {sys.getsizeof(p1)} bytes')  # ~56
print(f'dict: {sys.getsizeof(p2)} bytes')        # ~232
print(f'class: {sys.getsizeof(p3)} bytes')       # ~48 + __dict__

6.5.6 Praktische Beispiele

CSV-Daten verarbeiten:

from collections import namedtuple
import csv

# CSV-Daten
csv_data = """Name,Alter,Stadt
Anna,30,Flensburg
Bernd,25,Hamburg
Christian,35,Kiel"""

# namedtuple aus CSV-Header
lines = csv_data.strip().split('\n')
header = lines[0].split(',')
Person = namedtuple('Person', header)

# Daten parsen
people = []
for line in lines[1:]:
    values = line.split(',')
    person = Person(*values)
    people.append(person)

for p in people:
    print(f'{p.name} ist {p.age} Jahre alt und aus {p.city}')

Koordinaten-System:

from collections import namedtuple
import math

Point = namedtuple('Point', 'x y')

def distance(p1, p2):
    """Euklidische Distanz zwischen zwei Punkten"""
    return math.sqrt((p2.x - p1.x)**2 + (p2.y - p1.y)**2)

p1 = Point(0, 0)
p2 = Point(3, 4)

print(f'Distanz: {distance(p1, p2)}')  # 5.0

RGB-Farben:

from collections import namedtuple

Color = namedtuple('Color', 'red green blue')

# Vordefinierte Farben
BLACK = Color(0, 0, 0)
WHITE = Color(255, 255, 255)
RED = Color(255, 0, 0)

def to_hex(color):
    return f'#{color.red:02x}{color.green:02x}{color.blue:02x}'

print(to_hex(RED))  # #ff0000

6.6 Zusammenfassung

CollectionVerwendungVorteil
CounterElemente zählenEinfache Häufigkeitsanalyse
defaultdictDictionary mit Auto-InitialisierungKein KeyError, weniger Code
dequeQueue/Stack mit Zugriff an beiden EndenO(1) append/pop an beiden Enden
ChainMapMehrere Dictionaries verkettenKonfiguration mit Fallbacks
namedtupleTupel mit benannten FeldernLesbar, leichtgewichtig

Das collections-Modul bietet spezialisierte Datenstrukturen für häufige Anwendungsfälle, die effizienter und lesbarer sind, als selbstgebaute Lösungen.