Magic Methods für Container
Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 35 von 64.
Container-Magic-Methoden ermöglichen es Ihren Klassen, sich wie integrierte Container (Listen, Dictionaries, etc.) zu verhalten. Sie ermöglichen Indizierung, Längenprüfung und Iteration für Ihre benutzerdefinierten Objekte.
Hier ist ein Beispiel für eine Klasse mit Container-Magic-Methoden:
class CustomList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
def __iter__(self):
return iter(self.items)
def __contains__(self, item):
return item in self.itemsDie __len__-Methode lässt len() funktionieren:
my_list = CustomList([1, 2, 3, 4])
print(len(my_list)) # 4Die __getitem__ Methode ermöglicht die Indizierung zum Abrufen:
print(my_list[2]) # 3
print(my_list[0]) # 1Die Methode __setitem__ ermöglicht die Indizierung für Zuweisungen:
my_list[1] = 10
print(my_list[1]) # 10Die __contains__-Methode sorgt dafür, dass der in-Operator funktioniert:
print(3 in my_list) # True
print(100 in my_list) # FalseDie __iter__-Methode ermöglicht die Iteration:
for item in my_list:
print(item)Ausgabe:
4
3
1
10
True
False
1
10
3
4Kernpunkt: Magische Container-Methoden wie __len__, __getitem__, __setitem__, __iter__ und __contains__ lassen Ihre benutzerdefinierten Klassen sich wie integrierte Container verhalten. Dies ermöglicht intuitives Indizieren, Iterieren und Prüfen auf Mitgliedschaft für Ihre Objekte.
Aufgabe
MittelIn dieser Herausforderung implementierst du eine Deck-Klasse, die ein Kartenspiel mit umfassender Funktionalität und unter Einhaltung der Python-Konventionen simuliert.
Du musst nur die Datei deck.py bearbeiten. Folge den TODO-Kommentaren im Code, die dich durch die Implementierung führen:
- Initialisierung eines Standard-Kartenspiels mit 52 Karten (unter Verwendung von Strings wie "2H", "KD", "AS")
- Unterstützung für Pythons integrierte Operationen:
- Indizierung (
deck[0]) - Längenprüfung (
len(deck)) - Iteration (
for card in deck) - Mitgliedschaftsprüfung (
"AS" in deck)
- Indizierung (
- Eine
shuffle-Methode, um die Reihenfolge der Karten zu randomisieren
Spickzettel
Container-Magie-Methoden ermöglichen es Ihren Klassen, sich wie integrierte Container (Listen, Wörterbücher usw.) zu verhalten. Sie ermöglichen Indizierung, Längenprüfung und Iteration für Ihre benutzerdefinierten Objekte.
Wichtige Container-Magie-Methoden:
__len__()- ermöglicht dielen()-Funktion__getitem__()- ermöglicht die Indizierung zum Abrufen__setitem__()- ermöglicht die Indizierung zur Zuweisung__iter__()- ermöglicht die Iteration__contains__()- ermöglicht denin-Operator
class CustomList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
def __iter__(self):
return iter(self.items)
def __contains__(self, item):
return item in self.itemsAnwendungsbeispiele:
my_list = CustomList([1, 2, 3, 4])
# Längenprüfung
print(len(my_list)) # 4
# Indizierung
print(my_list[2]) # 3
my_list[1] = 10
# Mitgliedschaftsprüfung
print(3 in my_list) # True
# Iteration
for item in my_list:
print(item)Probier es selbst
from deck import Deck
# Umfassender Testfall-Handler
test_case = input()
def test_basic_functionality():
deck = Deck()
assert len(deck) == 52, f"Deck should have 52 cards, but has {len(deck)}"
first_card = deck[0]
assert isinstance(first_card, str), f"Card should be a string, but got {type(first_card)}"
assert "AS" in deck, "Ace of Spades should be in the deck"
assert "XY" not in deck, "XY is not a valid card and should not be in the deck"
cards = [card for card in deck]
assert len(cards) == 52, f"Iteration should yield 52 cards, but got {len(cards)}"
original_first_five = [deck[i] for i in range(5)]
deck.shuffle()
shuffled_first_five = [deck[i] for i in range(5)]
assert original_first_five != shuffled_first_five or len(deck) <= 5, "Shuffle should change card order"
print("Basic functionality tests passed!")
def test_edge_cases():
deck = Deck()
# Teste Zugriff auf die erste und letzte Karte
first_card = deck[0]
last_card = deck[51]
assert isinstance(first_card, str) and isinstance(last_card, str), "First and last cards should be strings"
# Teste negative Indizierung
assert deck[-1] == deck[51], "Negative indexing should work correctly"
# Teste Zugriff außerhalb der Grenzen
try:
invalid_card = deck[52]
print("Test failed: Should raise IndexError for out of bounds access")
except IndexError:
print("Edge case test passed: IndexError raised for out of bounds access")
print("Edge case tests passed!")
def test_card_uniqueness():
deck = Deck()
cards = [card for card in deck]
unique_cards = set(cards)
assert len(unique_cards) == 52, f"All cards should be unique, but found {len(unique_cards)} unique cards"
# Überprüfe, ob bestimmte Karten existieren
expected_cards = ["2H", "10S", "KD", "AC"]
for card in expected_cards:
assert card in deck, f"Expected card {card} not found in deck"
print("Card uniqueness tests passed!")
def test_shuffle_behavior():
deck = Deck()
original_order = [card for card in deck]
# Erstes Mischen
deck.shuffle()
first_shuffle = [card for card in deck]
assert len(first_shuffle) == 52, "Shuffle should preserve all 52 cards"
assert set(first_shuffle) == set(original_order), "Shuffle should not add or remove cards"
# Höchstwahrscheinlich hat sich die Reihenfolge geändert (obwohl eine winzige Wahrscheinlichkeit besteht, dass dies nicht der Fall war)
different_order = (original_order != first_shuffle)
# Zweites Mischen, um ganz sicher zu gehen
deck.shuffle()
second_shuffle = [card for card in deck]
different_order_2 = (first_shuffle != second_shuffle)
assert different_order or different_order_2, "Multiple shuffles should change the order"
print("Shuffle behavior tests passed!")
def test_contains_behavior():
deck = Deck()
# Teste, ob alle gültigen Karten im Deck sind
suits = ['H', 'D', 'C', 'S']
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
for suit in suits:
for rank in ranks:
card = rank + suit
assert card in deck, f"Valid card {card} should be in the deck"
# Teste, ob ungültige Karten nicht im Deck sind
invalid_cards = ["1H", "11S", "XD", "AX", "JX", ""]
for card in invalid_cards:
assert card not in deck, f"Invalid card {card} should not be in the deck"
print("Contains behavior tests passed!")
def test_iteration_behavior():
deck = Deck()
# Teste Iteration
card_count = 0
for card in deck:
card_count += 1
assert isinstance(card, str), f"Each card should be a string, but got {type(card)}"
assert card_count == 52, f"Iteration should yield 52 cards, but got {card_count}"
# Teste mehrfache Iterationen
first_iteration = [card for card in deck]
second_iteration = [card for card in deck]
assert first_iteration == second_iteration, "Multiple iterations should yield the same order"
print("Iteration behavior tests passed!")
# Führe den entsprechenden Test basierend auf der Eingabe aus
if test_case == "basic_functionality":
test_basic_functionality()
elif test_case == "edge_cases":
test_edge_cases()
elif test_case == "card_uniqueness":
test_card_uniqueness()
elif test_case == "shuffle_behavior":
test_shuffle_behavior()
elif test_case == "contains_behavior":
test_contains_behavior()
elif test_case == "iteration_behavior":
test_iteration_behavior()
else:
# Standardtest - führe die ursprüngliche Testsuite aus
def test_deck():
try:
# Teste Initialisierung und Länge
deck = Deck()
assert len(deck) == 52, f"Deck should have 52 cards, but has {len(deck)}"
# Teste getitem
first_card = deck[0]
assert isinstance(first_card, str), f"Card should be a string, but got {type(first_card)}"
# Teste contains
assert "AS" in deck, "Ace of Spades should be in the deck"
assert "XY" not in deck, "XY is not a valid card and should not be in the deck"
# Teste Iteration
cards = [card for card in deck]
assert len(cards) == 52, f"Iteration should yield 52 cards, but got {len(cards)}"
assert len(set(cards)) == 52, "All cards in the deck should be unique"
# Teste Mischen (grundlegende Prüfung, ob sich die Reihenfolge ändert)
original_first_five = [deck[i] for i in range(5)]
deck.shuffle()
shuffled_first_five = [deck[i] for i in range(5)]
assert original_first_five != shuffled_first_five or len(deck) <= 5, "Shuffle should change card order"
# Überprüfe, ob beim Mischen keine Karten verloren gehen
assert len(deck) == 52, f"Deck should still have 52 cards after shuffle, but has {len(deck)}"
print("All tests passed!")
except AssertionError as e:
print(f"Test failed: {e}")
test_deck()
print("Tests completed")Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktor-Methode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDie super()-FunktionMethoden überschreibenMehrfachvererbungMethod Resolution OrderZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden
Einführung in Magic MethodsOperator-ÜberladungMagic Methods für ContainerRückblick - Eigene Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung2Dekoratoren
Einführung in DekoratorenProperty-DekoratorStatischer Methoden-DekoratorKlassenmethoden-Dekorator5Polymorphismus
Methoden-Überschreiben vertieftDuck TypingAbstrakte Klassen und MethodenInterface-DesignZusammenfassung – Formen-Rechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische und KlassenmethodenKlassendekoratorenContext Manager3Klasseneigenschaften
Instanz- vs. KlassenvariablenProperty-DekoratorenPrivate AttributeZusammenfassung – Bankkonto-Manager6Kapselung
Public, Protected, Private MemberZugriffsmodifikatorenInformation HidingProperty-Decorators für FortgeschritteneZusammenfassung - Studentenverwaltungssystem12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen