Property-Decorators für Fortgeschrittene
Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 31 von 64.
Fortgeschrittene Property-Decorators bieten eine ausgefeiltere Kontrolle über den Attributzugriff, einschließlich berechneter Eigenschaften, Deleter und vollständiger Eigenschaftsverwaltung.
Hier ist ein Beispiel für berechnete Eigenschaften, die Werte von anderen Attributen ableiten:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
@property
def perimeter(self):
return 2 * (self.width + self.height)Verwenden Sie berechnete Eigenschaften wie reguläre Attribute:
rect = Rectangle(5, 3)
print(rect.area) # 15 - automatisch berechnet
print(rect.perimeter) # 16 - automatisch berechnetErstellen Sie eine Eigenschaft mit Getter, Setter und Deleter:
class Temperature:
def __init__(self):
self._temp = 0
@property
def temperature(self):
return self._temp
@temperature.setter
def temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below absolute zero!")
self._temp = value
@temperature.deleter
def temperature(self):
print("Resetting temperature to 0")
self._temp = 0Nutzen Sie die volle Property-Funktionalität:
temp = Temperature()Verwenden Sie den Setter mit Validierung:
temp.temperature = 25
print(temp.temperature) # 25
# temp.temperature = -300 # Würde einen ValueError auslösenVerwenden Sie den Deleter:
del temp.temperature
print(temp.temperature) # 0Erstellen Sie ein komplexeres Beispiel mit einem Spielstand:
class Player:
def __init__(self, name):
self.name = name
self._score = 0
self._level = 1
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if value >= 0:
self._score = value
self._level = (value // 1000) + 1
else:
raise ValueError("Score cannot be negative")
@score.deleter
def score(self):
print(f"Resetting {self.name}'s progress")
self._score = 0
self._level = 1
@property
def level(self):
return self._level
player = Player("Alice")
player.score = 2500
print(f"Score: {player.score}, Level: {player.level}") # Score: 2500, Level: 3
del player.score
print(f"Score: {player.score}, Level: {player.level}") # Score: 0, Level: 1Ausgabe:
15
16
25
Resetting temperature to 0
0
Score: 2500, Level: 3
Resetting Alice's progress
Score: 0, Level: 1Kernpunkt: Fortgeschrittene Property-Dekoratoren ermöglichen berechnete Eigenschaften (berechnet aus anderen Daten), das Löschen von Eigenschaften mit @property.deleter sowie die vollständige Kontrolle über das Abrufen, Setzen und Löschen von Attributen. Dies schafft intuitive Schnittstellen, während gleichzeitig eine starke Datenvalidierung und Kapselung beibehalten wird.
Aufgabe
MittelIn dieser Herausforderung implementieren Sie eine Rectangle-Klasse mit ordnungsgemäßer Kapselung und Eigenschaftsvalidierung.
rectangle.py- Dies ist die Datei, die Sie bearbeiten müssen; sie enthält TODO-Kommentare, die Sie bei der Implementierung unterstützendriver.py- Enthält umfangreiche Testszenarien (nicht ändern)
- Implementieren Sie private Attribute für
_widthund_height - Erstellen Sie Eigenschaften für
widthundheightmit Validierung (müssen positiv sein)- Lösen Sie entsprechende ValueError-Meldungen aus, wie in den TODOs angegeben
- Wichtig: Prüfen Sie, ob der Wert kleiner oder gleich 0 ist, und lösen Sie dann den Fehler aus (dies stellt ein konsistentes Verhalten sicher)
- Implementieren Sie schreibgeschützte Eigenschaften für
areaundperimeter - Erstellen Sie eine
dimensions-Eigenschaft mit Getter-, Setter- und Deleter-Funktionalität, wie in den TODOs beschrieben- Wichtig: Verwenden Sie im Setter die Syntax für das Entpacken von Tupeln:
width, height = dimensions
- Wichtig: Verwenden Sie im Setter die Syntax für das Entpacken von Tupeln:
Spickzettel
Fortgeschrittene Property-Dekoratoren bieten eine anspruchsvolle Kontrolle über den Attributzugriff mit berechneten Eigenschaften, Deletern und vollständiger Eigenschaftsverwaltung.
Berechnete Eigenschaften:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
@property
def perimeter(self):
return 2 * (self.width + self.height)Vollständige Eigenschaft mit Getter, Setter und Deleter:
class Temperature:
def __init__(self):
self._temp = 0
@property
def temperature(self):
return self._temp
@temperature.setter
def temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below absolute zero!")
self._temp = value
@temperature.deleter
def temperature(self):
print("Resetting temperature to 0")
self._temp = 0Verwendung:
# Berechnete Eigenschaften
rect = Rectangle(5, 3)
print(rect.area) # 15
print(rect.perimeter) # 16
# Vollständige Eigenschaftsfunktionalität
temp = Temperature()
temp.temperature = 25 # Verwendet Setter
print(temp.temperature) # Verwendet Getter
del temp.temperature # Verwendet DeleterProbier es selbst
from rectangle import Rectangle
# Testfall-Handler
test_case = input()
# Grundlegender Funktionstest
if test_case == "default_test":
rect = Rectangle(5, 3)
print(f"Width: {rect.width}, Height: {rect.height}")
print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")
# Teste die dimensions-Eigenschaft
print(f"Dimensions: {rect.dimensions}")
rect.dimensions = (10, 8)
print(f"New area: {rect.area}")
# Teste Validierung
try:
rect.width = -2
except ValueError as e:
print(f"Validation error: {e}")
# Teste Deleter
del rect.dimensions
print(f"After reset: {rect.dimensions}")
# Test mit Nullwerten
elif test_case == "zero_values":
try:
rect = Rectangle(0, 5)
except ValueError as e:
print(f"Error creating rectangle: {e}")
try:
rect = Rectangle(5, 0)
except ValueError as e:
print(f"Error creating rectangle: {e}")
# Test mit negativen Werten
elif test_case == "negative_values":
rect = Rectangle(5, 3)
original_dimensions = rect.dimensions
try:
rect.dimensions = (5, -3)
except ValueError as e:
print(f"Error setting dimensions: {e}")
print(f"Dimensions after failed update: {rect.dimensions}")
print(f"Original dimensions preserved: {rect.dimensions == original_dimensions}")
# Test mit großen Werten
elif test_case == "large_values":
rect = Rectangle(1000000, 2000000)
print(f"Large rectangle area: {rect.area}")
print(f"Large rectangle perimeter: {rect.perimeter}")
# Test mit Fließkommawerten
elif test_case == "float_values":
rect = Rectangle(3.5, 2.75)
print(f"Dimensions: {rect.dimensions}")
print(f"Area: {rect.area}")
print(f"Perimeter: {rect.perimeter}")
rect.dimensions = (1.1, 2.2)
print(f"New area with float dimensions: {rect.area}")
# Test mit Typfehlern
elif test_case == "type_errors":
try:
rect = Rectangle("5", 3)
except Exception as e:
print(f"Type error during creation: {type(e).__name__}: {e}")
rect = Rectangle(5, 3)
try:
rect.dimensions = 10 # Kein Tupel
except Exception as e:
print(f"Type error setting dimensions: {type(e).__name__}: {e}")
# Teste mehrere Eigenschaftsoperationen
elif test_case == "property_operations":
rect = Rectangle(5, 10)
print(f"Initial - Width: {rect.width}, Height: {rect.height}, Area: {rect.area}")
rect.width = 8
print(f"After width change - Width: {rect.width}, Area: {rect.area}")
rect.height = 6
print(f"After height change - Height: {rect.height}, Area: {rect.area}")
rect.dimensions = (12, 9)
print(f"After dimensions change - Dimensions: {rect.dimensions}, Area: {rect.area}")
del rect.dimensions
print(f"After reset - Dimensions: {rect.dimensions}, Area: {rect.area}")
# Teste Grenzfälle der Eigenschaftsvalidierung
elif test_case == "validation_edge_cases":
rect = Rectangle(5, 3)
try:
rect.width = 0
except ValueError as e:
print(f"Zero width error: {e}")
# Sehr kleiner positiver Wert sollte akzeptiert werden
rect.height = 0.0001
print(f"Small height accepted: {rect.height}")
print(f"Area with small height: {rect.area}")
# Teste mehrere Rechtecke
elif test_case == "multiple_rectangles":
rect1 = Rectangle(5, 3)
rect2 = Rectangle(10, 2)
rect3 = Rectangle(4, 4)
print(f"Rectangle 1 - Area: {rect1.area}, Perimeter: {rect1.perimeter}")
print(f"Rectangle 2 - Area: {rect2.area}, Perimeter: {rect2.perimeter}")
print(f"Rectangle 3 - Area: {rect3.area}, Perimeter: {rect3.perimeter}")
# Modifiziere jedes Rechteck
rect1.width = 7
rect2.height = 5
rect3.dimensions = (6, 6)
print(f"After modifications:")
print(f"Rectangle 1 - Dimensions: {rect1.dimensions}")
print(f"Rectangle 2 - Dimensions: {rect2.dimensions}")
print(f"Rectangle 3 - Dimensions: {rect3.dimensions}")
# Teste Performance mit vielen Operationen
elif test_case == "performance_test":
rect = Rectangle(5, 5)
# Führe viele Eigenschaftsoperationen aus
for i in range(1000):
rect.width = i % 10 + 1 # Werte 1-10
rect.height = i % 5 + 1 # Werte 1-5
area = rect.area # Zugriff auf berechnete Eigenschaft
perimeter = rect.perimeter # Zugriff auf berechnete Eigenschaft
dims = rect.dimensions # Zugriff auf Eigenschafts-Getter
print(f"Final state after 1000 operations:")
print(f"Width: {rect.width}, Height: {rect.height}")
print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")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