Ich habe eine Klasse, die ein Mitgliedsobjekt enthält. Ich möchte die Methoden des Mitglieds aufrufen, als ob sie Methoden der Containerklasse wären.
Das folgende Beispiel veranschaulicht (allerdings in einem anderen Kontext), was ich gerne tun würde.
Angenommen, wir haben zwei Klassen, die zwei verschiedene Arten von Produkten repräsentieren: Spielzeug y Schuhe . Jede Klasse hat zwei Methoden, sagen wir mal, weight()
y description()
die natürlich das Gewicht des Artikels und die Beschreibung des Artikels zurückgeben.
Jetzt möchte ich diese Produkte in einzelnen Boxen - jedes Feld enthält entweder ein einzelnes Toy
entweder eine einzelne Shoe
.
Ich möchte weiterhin auf die Methoden zugreifen können weight()
y description()
Ich möchte jedoch, dass sie Mitglieder der Box
Instanz. Außerdem möchte ich die Methoden nicht speziell implementieren weight()
y description()
im Box
Klasse, denn ich möchte nicht noch mehr Methoden in die Box
Klasse, wenn eine neue Methode zu Toy und Shoe hinzugefügt wird.
Hier ist ein Beispiel für das "Endergebnis", das mich glücklich machen würde:
# Define our products
product1 = Toy('plastic gun', 200)
product2 = Shoe('black leather shoes', 500)
# Now place them in boxes
box1 = Box(product1, box_code='A1234')
box2 = Box(product2, box_code='V4321')
# I want to know the contents of the boxes
box1.description()
box2.description()
# Desired results
>> plastic gun
>> black leather shoes
Meine Idee zur Umsetzung ist folgende.
class Product():
def __init__(self, description, weight):
self.desc = description
self.wght = weight
def description(self):
return self.desc
def weight(self):
return self.weight
class Toy(Product):
pass
class Shoe(Product):
pass
class Box(object):
def __init__(self, product, box_code):
self.box_code = box_code
self.product = product
def __getattribute__(self, name):
# Any method that is accessed in the Box instance should be replaced by
# the correspondent method in self.product
return self.product.__getattribute__(name)
Das funktioniert aber nicht! Wenn ich das "gewünschte" Beispiel, das im ersten Codeblock gezeigt wird, ausführe, erhalte ich eine unendliche Rekursion. Wie kann man das elegant lösen?
Beachten Sie, dass Box
hat einen eigenen Parameter box_code
und dass ich in Zukunft vielleicht neue Methoden zu Toy
y Shoes
(z.B. einen Werbecode oder was auch immer), ohne die Klasse ändern zu müssen Box
.
Okay Leute, ich warte gespannt auf eure Antworten.
Update : Antwort auf das Problem Vielen Dank an Interjay und an Mike Boer für ihre Hilfe.
Ich musste nur die Definition der Methode ersetzen __getattribute__
in der Klasse Box
von __getattr__
und es funktionierte perfekt, wie von Interjay vorgeschlagen. Die korrigierte Definition der Klasse Box lautet:
class Box(object):
def __init__(self, product, box_code):
self.box_code = box_code
self.product = product
def __getattr__(self, name):
# Any method that is accessed in the Box instance should be replaced by
# the correspondent method in self.product
return self.product.__getattribute__(name)
Update : Vervollständigung des Beispiels mit __setattr__
Nachdem ich das Problem mit der getattr-Methode behoben hatte, bemerkte ich, dass meine Klassen nicht das gewünschte Verhalten zeigten, wenn ich ein Attribut setzen wollte. Zum Beispiel, wenn ich versuchte:
box1.desc = 'plastic sword'
Anstatt die Beschreibung von Produkt1 zu ändern (die in Feld1 eingekapselt war), wurde ein neues Mitglied namens "desc" in Feld1 erstellt. Um dieses Problem zu lösen, musste ich das Element __setattr__
Funktion, wie unten dargestellt:
def __setattr__(self, name, value):
setattr(self.product, name, value)
Durch das Hinzufügen dieser Funktion wird jedoch ein rekursiver Aufruf erzeugt, da in __init__
Ich versuche zuzuordnen self.product = product
', die die Funktion __setattr__
die das Mitglied nicht findet self.product
auf, ruft also die Funktion __setattr__
wieder, rekursiv ad infinitum.
Um dieses Problem zu vermeiden, muss ich die __init__
Methode, um das neue Mitglied über das Wörterbuch der Klasse zuzuweisen. Die vollständige Definition der Klasse Box
ist dann:
class Box(object):
def __init__(self, product, box_code):
self.__dict__['product'] = product
self.box_code = box_code
def __getattr__(self, name):
# Any method that is accessed in the Box instance should be replaced by
# the correspondent method in self.product
return getattr(self.product, name)
def __setattr__(self, name, value):
setattr(self.product, name, value)
Jetzt eine lustige Sache... Wenn ich zuerst das Mitglied definiere self.product
wie oben gezeigt, funktioniert das Programm normal. Wenn ich jedoch versuche, zuerst das Mitglied zu definieren self.box_code
leidet das Programm erneut unter dem Problem der rekursiven Schleife. Weiß jemand, warum?