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)

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]

List comprehension sind in einigen Fällen besser lesbar, können jedoch auch schnell unübersichtlich werden. Sie sind auch mit if-Bedingungen möglich.

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 die selbe 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

Mehr zu Listen unter: https://www.programiz.com/python-programming/methods/list

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

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:
baujahr = {'Ford': 2019, 'Honda': 2013}
print(baujahr)  # {'Ford': 2019, 'Honda': 2013}

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

# Möglichkeit 3: Schlüssel werden als Tupel übergeben)
baujahr = dict.fromkeys( ('Ford', 'Honda') )
baujahr['Ford'] = 2019
baujahr['Honda'] = 2013
print(baujahr)  # {'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

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

Das collections-Modul bietet spezialisierte Container-Datentypen, die über die eingebauten Listen, Tupel, Dictionaries und Sets hinausgehen.

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 = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
counter = Counter(words)
print(counter)  # Counter({'apple': 3, 'banana': 2, 'cherry': 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 = ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob', 'Alice']
counter = Counter(votes)

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

# Alle Elemente nach Häufigkeit
print(counter.most_common())   # [('Alice', 3), ('Bob', 2), ('Charlie', 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['fruits'].append('apple')
d['fruits'].append('banana')
d['vegetables'].append('carrot')

print(d)  # defaultdict(<class 'list'>, {'fruits': ['apple', 'banana'], 'vegetables': ['carrot']})

# 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 = [
    ('Alice', 'Math'),
    ('Bob', 'Physics'),
    ('Charlie', 'Math'),
    ('Diana', 'Physics'),
    ('Eve', 'Math')
]

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

print(dict(by_subject))
# {'Math': ['Alice', 'Charlie', 'Eve'], 'Physics': ['Bob', 'Diana']}

Verschachtelte defaultdict:

from collections import defaultdict

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

users['john']['age'] = 30
users['john']['city'] = 'New York'
users['alice']['age'] = 25

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

6.3 deque – Double-Ended Queue

deque (ausgesprochen “deck”) ist eine Liste, die für schnelle Zugriffe an beiden Enden optimiert ist.

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.5s
  • Deque appendleft: ~0.01s

6.3.5 Praktische Beispiele

FIFO-Queue (First In, First Out):

from collections import deque

queue = deque()

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

# Elemente verarbeiten (FIFO)
while queue:
    task = queue.popleft()
    print(f"Processing: {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)

Wichtig: 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('Alice', 30)

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

# Klasse
class PersonClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age
p3 = PersonClass('Alice', 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,age,city
Alice,30,New York
Bob,25,London
Charlie,35,Paris"""

# 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} is {p.age} years old from {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"Distance: {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

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