Seite 1 von 1
Attribute Basisklasse / Unterklasse
Verfasst: Donnerstag 11. November 2010, 11:28
von mutetella
Hallo...
Ich habe folgendes Modell:
Code: Alles auswählen
class Recurrence(object):
def __init__(self, foo, bar):
self.end_date = self.list_match(self._recurrence_len)
class MonthlyRecurrence(Recurrence):
def __init__(self, foo, bar):
Recurrence.__init__(self, foo, bar)
def _recurrence_len(self):
return monthly_foo
YearlyRecurrence(MonthlyRecurrence):
def __init__(self, foo, bar):
MonthlyRecurrence.__init__(self, foo, bar)
def _recurrence_len(self):
return yearly_foo
Wenn ich nun eine Instanz von YearlyRecurrence() erstelle, wird ja die __init__ von MonthlyRecurrence() aufgerufen, die wiederum die __init__ von Recurrence() aufruft, innerhalb der dann self._recurrence_len(), in dem Fall also Monthly._recurrence_len() abgefragt wird.
Wie kann ich es erreichen, dass innerhalb der Recurrence.__init__() die self._recurrence_len() in Abhängigkeit der "untersten" Klasse aufgerufen wird. Bei einer YearlyRecurrence()-Instanz eben die YearlyRecurrence._recurrence_len(), bei einer MonthlyRecurrence()-Instanz die MonthlyRecurrence._recurrence_len().
Bringt mich hier super() weiter? Oder ist gar meine Konstruktion so nicht optimal?
:K
Gruß
mutetella
Re: Woher komme ich?
Verfasst: Donnerstag 11. November 2010, 11:50
von EyDu
Mal abgesehen davon, dass du in deinem Beispiel nie "_recurrence_len" aufrufst, aber dein gewünschtes Verhalten ist das Standardverhalten. Also ist dein Code entweder nicht der, welcher den Fehler erzeugt oder du interpretierst deine Ergebnisse falsch.
Re: Woher komme ich?
Verfasst: Donnerstag 11. November 2010, 11:50
von ws
Hallo Mutetella,
wenn ich das richtig sehe, muss Du dafür gar nix tun. Pythons Methoden sind erstmal standardmässig virtuell, d.h. sie werden von abgeleiteten Implementierungen ggf. überschrieben. Erzeugst Du eine Instanz von YearlyRecurrence, ändert die Tatsache, dass Du im Initializer noch MonthlyRecurrence.__init__ aufrufst, nichts an der Tatsache, dass Deine Instanz vom Typ YearlyRecurrence ist. Python ruft dann automatisch die Methode der am besten passenden Klasse auf "s. Python Method resolution order", was in diesem Fall YearlyRecurrence._recurrence_len() ist.
Gruss
Wolfgang
Re: Woher komme ich?
Verfasst: Donnerstag 11. November 2010, 13:49
von pillmuncher
@mutetella: Ein jährlich wiederkehrendes Ereignis ist kein monatlich wiederkehrendes Ereignis. Deine Vererbungsstruktur sollte das widerspiegeln.
Gruß,
Mick.
Re: Woher komme ich?
Verfasst: Donnerstag 11. November 2010, 15:44
von mutetella
EyDu hat geschrieben:... dass du in deinem Beispiel nie "_recurrence_len" aufrufst, ...
Sorry, müsste natürlich
Code: Alles auswählen
class Recurrence(object):
def __init__(self, foo, bar):
self.end_date = self.list_match(self._recurrence_len())
heissen...
ws hat geschrieben:Python ruft dann automatisch die Methode der am besten passenden Klasse auf "s. Python Method resolution order", was in diesem Fall YearlyRecurrence._recurrence_len() ist.
Jepp, wie mir soeben aufgefallen ist, liegt der Fehler auch an anderer Stelle:
Beide Klassen, sowohl MonthlyRecurrence() wie auch YearlyRecurrence() legen beim Instanziieren ein Attribut self.interval an. Beim Instanziieren von YearlyRecurrence() erhält die Basisklasse als interval-Attribut immer den Wert 1. 'interval' wird dann in der jeweiligen _recurrence_len() zur Berechnung verwendet. Um das ganze zu vereinfachen, habe ich den Ablauf mal als kleines Modell abgebildet:
Code: Alles auswählen
class Recurrence(object):
def __init__(self, interval):
self.interval = interval
print(self.get_interval())
class MonthlyRecurrence(Recurrence):
def __init__(self, interval):
First.__init__(self, interval)
self.interval = interval
print(self.get_interval())
def get_interval(self):
return self.interval
class YearlyRecurrence(MonthlyRecurrence):
def __init__(self, interval):
self.interval = interval
Second.__init__(self, 1)
print(self.get_interval())
def get_intervclass Recurrence(object):
def __init__(self, interval):
self.interval = interval
print(self.get_interval())
Warum erhalte ich hier folgende Ausgabe?
Code: Alles auswählen
In [176]: y = YearlyRecurrence(3)
1
1
1
In [177]: y.interval
Out[177]: 1
pillmuncher hat geschrieben:Ein jährlich wiederkehrendes Ereignis ist kein monatlich wiederkehrendes Ereignis.
Monatliche Wiederholung: Jeden 1. und 15. des Monats
Jährliche Wiederholung: Alle 2 Jahre am 1. und 15. Januar im Januar und März
Ich habe also in einer jährlichen Wiederholung lediglich den Jahresinterval und die Angabe von Monaten. Ich war da jetzt ganz pragmatisch und hab' von MonthlyRecurrence() geerbt, damit ich die Abfrage nur noch um den Jahresinterval und die Monate erweitern muss. Hier der ganze Code:
http://paste.pocoo.org/show/289815/
Vielleicht hast Du ja Lust, da mal drüberzuschauen.
Gruß
mutetella
Re: Woher komme ich?
Verfasst: Donnerstag 11. November 2010, 15:48
von EyDu
Es fehlt irgendwie noch, was du als Ausgabe erwartest

Ich vermute mal, dass du als Ausgabe eine 3 erwartest. Dann solltest du dir über die Reihenfolge von
Code: Alles auswählen
def __init__(self, interval):
self.interval = interval
Second.__init__(self, 1)
Gedanken machen.
Re: Woher komme ich?
Verfasst: Donnerstag 11. November 2010, 20:11
von mutetella
Also erstmal sorry für meine schlampige Fragestellung und das fehlerhafte Codebeispiel...

Das mit der Reihenfolge war natürlich ein ganz doofer Fehler! Und von Recurrence() erben zu wollen, in der __init__() aber Second() aufzurufen zeugt auch nicht gerade von einem klaren Verstand...
Hier also nochmal das jetzt korrekte Beispiel:
Code: Alles auswählen
class Recurrence(object):
def __init__(self, interval):
self.interval = interval
print(self.get_interval())
class MonthlyRecurrence(Recurrence):
def __init__(self, interval):
Recurrence.__init__(self, interval)
self.interval = interval
print(self.get_interval())
def get_interval(self):
return 'MonthlyRecurrence: %i' % self.interval
class YearlyRecurrence(MonthlyRecurrence):
def __init__(self, interval):
MonthlyRecurrence.__init__(self, 1)
self.interval = interval
print(self.get_interval())
def get_interval(self):
return 'YearlyRecurrence: %i' % self.interval
Als Ausgabe erhalte ich:
Code: Alles auswählen
In [206]: y = YearlyRecurrence(3)
YearlyRecurrence: 1
YearlyRecurrence: 1
YearlyRecurrence: 3
Ich verstehe nicht, dass, auch wenn immer die YearlyRecurrence.get_interval() aufgerufen wird, dabei nicht immer die self.interval der YearlyRecurrence()-Instanz verwendet wird. Selbst wenn ich die YearlyRecurrence.__init__() folgendermaßen ändere...
Code: Alles auswählen
def __init__(self, interval):
self.interval = interval
MonthlyRecurrence.__init__(self, 1)
self.interval = interval
print(self.get_interval())
...verwendet YearlyRecurrence.get_interval() beim 1. und 2. Aufruf die self.interval aus MonthlyRecurrence(), erst beim 3. Aufruf aus YearlyRecurrence() wird dann auch die self.interval aus YearlyRecurrence() ausgegeben.
Als ich diesen Thread eröffnete, dachte ich noch, dass die "falschen" Methoden aufgerufen werden. An der Ausgabe ist aber zu sehen, dass die aufgerufene Methode richtigerweise die Methode aus YearlyRecurrence() ist. Nur das verwendete Attribut nicht.
Warum ist das so?
Gruß
mutetella
Re: Woher komme ich?
Verfasst: Donnerstag 11. November 2010, 20:55
von DaMutz
mutetella hat geschrieben:Warum ist das so?
ganz einfach

:
- YearlyRecurrence.__init__ wird aufgerufen
- MonthlyRecurrence.__init__ wird aufgerufen
- Recurrence.__init__ wird aufgerufen
- self.interval wird auf 1 gesetzt (in Recurrence.__init__)
- self.interval wird ausgegeben (in YearlyRecurrence.get_interval) -> 1
- self.interval wird auf 1 gesetzt (in MonthlyRecurrence.__init__)
- self.interval wird ausgegeben (in YearlyRecurrence.get_interval) -> 1
- self.interval wird auf 3 gesetzt (in YearlyRecurrence.__init__)
- self.interval wird ausgegeben (in YearlyRecurrence.get_interval) -> 3
Verstehst du es jetzt?
Re: Woher komme ich?
Verfasst: Donnerstag 11. November 2010, 21:00
von EyDu
Das ist nicht unerwartet. ich mache es mal schrittweise:
1. Du rufst die __init__ von YearlyRecurrence auf
2. Darin rufst du die __init__ von MonthlyRecurrence mit dem Wert 1 auf
3. Nun wird die __init__ von Recurrence aufgerufen, wieder mit dem Wert 1
4. self.interval setzt du nun auf 1
5. Jetzt rufst du self.get_interval auf, welches natürlich nun 1 ausgibt
6. Du fällst zurück in die __init__ von MonthlyRecurrence und setzt self.interval erneut auf 1
7. Nun gibt self.get_interval natürlich 1 aus
8. Nun kommst du zurück in die __init__ von YearlyRecurrence und set self.interval auf 3, da diese an den Parameter interval gebunden ist
9. In self.get_interval wird nun korrekt die 3 ausgegeben
Edit: Da war ich wohl zu langsam
Re: Attribute Basisklasse / Unterklasse
Verfasst: Freitag 12. November 2010, 10:45
von mutetella
Und welche Möglichkeit habe ich, in der YearlyRecurrence()-Instanz interval auf die 3 zeigen zu lassen und in der Basisklasse MonthlyRecurrence() auf die 1?
Ich ging davon aus, dass die Basisklasse einen eigenen Namensraum hat. Ist nicht so?
Gruß
mutetella
Re: Attribute Basisklasse / Unterklasse
Verfasst: Freitag 12. November 2010, 11:10
von /me
mutetella hat geschrieben:Und welche Möglichkeit habe ich, in der YearlyRecurrence()-Instanz interval auf die 3 zeigen zu lassen und in der Basisklasse MonthlyRecurrence() auf die 1?
Gar nicht. Du hast ein Problem mit dem Konzept. Du hast nur eine einzige Instanz.
Was du möchtest sind entweder unterschiedliche Attributnamen für unterschiedliche Zwecke oder eine Liste in YearlyRecurrence die Instanzen vom Typ MonthlyRecurrence aufnimmt.
Re: Attribute Basisklasse / Unterklasse
Verfasst: Freitag 12. November 2010, 20:38
von mutetella
/me hat geschrieben:Du hast ein Problem mit dem Konzept.
Hab' ich dauernd...
/me hat geschrieben:... entweder unterschiedliche Attributnamen für unterschiedliche Zwecke oder eine Liste in YearlyRecurrence ...
Find' ich jetzt beides nicht wirklich "chic". Letztlich handelt es sich um 2 MonthlyRecurrence()-Methoden, die ich auch bei YearlyRecurrence()-Instanzen benötige. Wenn ich mir das jetzt so überlege, ist das überhaupt total idiotisch, deswegen von MonthlyRecurrence() zu erben.
Was würdest Du machen?
Soll ich
- a) die beiden Methoden als Funktionen auslagern oder
b) in die Basisklasse Recurrence() verlegen, auch wenn die Methoden dann nur von MonthlyRecurrence()- und YearlyRecurrence()-Instanzen genutzt werden, nicht aber von DailyRecurrence()- und WeeklyRecurrence()-Instanzen, die auch von Recurrence() erben. Wäre das ok? Oder sollten Basisklassen nicht ausschließlich Methoden bereitstellen, die dann auch von allen Unterklassen benötigt werden? Oder
c) ich lasse das mit den verschiedenen Klassen und verwende eine Idee von bwbg, die nicht jeden Wiederholungstyp in eine separate Klasse steckt, sondern Wiederholungen gewissermaßen aus einer Sammlung diverser Prüf-Funktionen bildet, siehe hier.
Gruß
mutetella