Methode an Klasse übergeben. Ist das ähnlich wie Vererbung?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

ich bastle gerade an einer Struktur, wie ich meine Kalendereinträge am besten verwalte.
Dazu arbeite ich mit 3 Klassen
  • Diary(): Legt für jeden Termin eine Entry()-Instanz an, nimmt Änderungen und Löschungen vor etceterapepe...
  • Entry(): Stellt einen Termin dar
  • DaySheet(): Nimmt entries eines bestimmten Tages auf, um dann an die TUI bzw. GUI übergeben zu werden. Wird aus Diary() heraus erstellt und erhält zu den entries auch eine Diary.update()-Methode, um Änderungen zurück an Diary() leiten zu können.
Jetzt zu meiner eigentlichen Frage: Geschieht mit der Übergabe der Diary.update()-Methode an die DaySheet()-Instanz etwas ähnliches wie bei einer Klassenvererbung? Die übergebene Methode befindet sich ja in einem völlig neuen Namensraum. Wie bleibt der Kontakt zur 'Heimatbasis' erhalten?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Nein das hat nichts mit Vererbung zu tun. Und was meinst Du mit "Kontakt zur 'Heimatbasis'"? Methoden auf Exemplaren sind Funktionen, deren erstes Argument an das Exemplar gebunden ist. Das `self` verweist ja auf das Objekt von dem die Methode als Attribut abgerufen wurde. Meinst Du das mit "Kontakt zur 'Heimatbasis'"?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

BlackJack hat geschrieben:Meinst Du das mit "Kontakt zur 'Heimatbasis'"?
Ja.

Nur, damit meine Verwirrung komplett wird: Wenn ich eine Klassenmethode (meinst Du mit "Methoden auf Exemplaren" dasselbe?) an eine andere Klasse übergebe, kann ich mir das 'self' der übergebenen Methode dann wie eine Leitung zur Klasse, aus der übergeben wurde, vorstellen? Weil beim Aufruf dieser Methode befindet sich diese ja nicht mehr in 'ihrem' Namensraum... :?
Um bei meinem Konstrukt zu bleiben: Wenn ich Diary.update() aus einer DaySheet()-Instanz heraus aufrufe, wie landen die Informationen in der Diary()-Instanz?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Äh, ja Verwirrung ist das Stichwort. *Klassenmethoden* sind für mich Methoden die mit `classmethod()` erstellt/behandelt wurden. Davon sehe ich in dem Beispiel jetzt gerade keine. :-)

Ansonsten gibt es Methoden in zwei Formen -- ungebunden auf Klassen-Objekten und gebunden auf Exemplaren. Im ersten Fall ist `self` noch ein Argument was man übergeben muss. Im zweiten Fall ist `self` an das Exemplar gebunden von dem die Methode abgerufen wurde.

Code: Alles auswählen

In [39]: class A(object):
   ....:     def meth(self):
   ....:         print self
   ....: 

In [40]: a = A()

In [41]: A.meth
Out[41]: <unbound method A.meth>

In [42]: A.meth(a)
<__main__.A object at 0x8eda12c>

In [43]: a
Out[43]: <__main__.A object at 0x8eda12c>

In [44]: a.meth()
<__main__.A object at 0x8eda12c>

In [45]: b = A()

In [46]: b
Out[46]: <__main__.A object at 0x8eda80c>

In [47]: b.meth()
<__main__.A object at 0x8eda80c>

In [48]: a.meth
Out[48]: <bound method A.meth of <__main__.A object at 0x8eda12c>>

In [49]: b.meth
Out[49]: <bound method A.meth of <__main__.A object at 0x8eda80c>>
Beseitigt das kleine Experiment alle Unklarheiten!?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

BlackJack hat geschrieben:Beseitigt das kleine Experiment alle Unklarheiten!?
Ich hab's begriffen, aber noch nicht wirklich verinnerlicht... :wink:

Werde jetzt einfach mal an meiner Konstruktion weiterbasteln, sehen, wie sich die Dinge verhalten, ob es sich bewährt und das, was ich meine verstanden zu haben auch bestätigt.
Ich hänge immer noch ein wenig an der offensichtlich falschen Vorstellung, dass die an das Diary()-Exemplar gebundene Methode (ist das so richtig?) 'update_entry()' bei der Übergabe an das DaySheet()-Exemplar gewissermaßen kopiert wird und dann dort auch verwendet wird. Damit bräuchte es ja dann sowas wie einen Server, der die Anfragen der Methoden verabeitet. Ist jetzt natürlich Blödsinn, aber so in etwa schaut meine Vorstellung noch aus...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
syntor
User
Beiträge: 88
Registriert: Donnerstag 2. Dezember 2010, 03:56

Ich würde das Lieber eine Diary-Instanz nennen.

Nein, die Methode wird sicherlich nicht kopiert.

Vorhin hast du dich darüber gewundert, dass "self nicht mehr im selben Namensraum ist", zu dem Zeitpunkt wo die Methode aufgerufen wird?

Ich verstehe nicht ganz was du meinst, aber was ich mir vorstellen könnte, ist folgendes: Du hast die Klasse verschachtelt, und greifst auf das self vom äusseren Scope zu. (Dann hättest du aber das "self" der verschachtelten Klasse umbenennen müssen?)

Ich denke es wäre einfacher dir zu helfen, wenn du den Sourcecode posten könntest.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

syntor hat geschrieben:Ich würde das Lieber eine Diary-Instanz nennen.
Um ehrlich zu sein: Mir ist noch gar nicht ganz klar, wo zwischen den beiden Begriffen 'Instanz' und 'Exemplar' der Unterschied liegt... :oops:
syntor hat geschrieben:Ich denke es wäre einfacher dir zu helfen, wenn du den Sourcecode posten könntest.
Wie schon gesagt, ich bin da erst am tüfteln, kann da also noch nix gescheites posten. Ich versuch' mal, einen groben Umriß zu zeichnen:

Code: Alles auswählen

class Diary(object):
    def __init__(self):
        self._entries = []

    def set_entry(self, **entry_args):
        self._entries.append(Entry(**entry_args))

    def update_entry(self, index, **entry_args):
        for attribut in entry_args.iterkeys():
            setattr(self._entries[index], attribut, entry_args[attribut])

    def get_daysheet(self, date):
        entries = [entry for entry in self._entries if
            entry.is_match(date)]
        return DaySheet(self.update_entry, self._entries)

class DaySheet(object):
    def __init__(self, update, entries):
        self.update = update
        self.entries = entries

class Entry(object):
    ...
Mein Unverständnis besteht eben teilweise noch darin, was passiert, wenn ich via

Code: Alles auswählen

diary = Diary()
diary.set_entry(...)

daysheet = diary.get_daysheet(...)
dann daysheet.update(...) aufrufe. Besser noch: Wo passiert das daysheet.update()? In der DaySheet- oder der Diary()-Instanz?

Oder kann man das so nicht beantworten, weil die Frage hirnrissig ist? :)

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

mutetella hat geschrieben:
syntor hat geschrieben:Ich würde das Lieber eine Diary-Instanz nennen.
Um ehrlich zu sein: Mir ist noch gar nicht ganz klar, wo zwischen den beiden Begriffen 'Instanz' und 'Exemplar' der Unterschied liegt... :oops:
Die Beiden sind Synonymk.
mutetella hat geschrieben:daysheet.update(...) aufrufe
Wo ist da denn ein `daysheet.update`? Aber nein, eine Methode gehoert immer zu dem Objekt auf dem es aufgerufen wird[1]. Das `self` bzw das 1. Argument der Methode wird automatisch daran gebunden und kommt _nicht_ aus dem lexikalischen Scope.


[1] Ausnahme: Unbound methods, aber denen uebergibt man das `self` sowieso explizit.
syntor
User
Beiträge: 88
Registriert: Donnerstag 2. Dezember 2010, 03:56

Ich habe bloss den Begriff "Exemplar" in diesem Zusammenhang noch nie gehört, das mag aber auch daran liegen, dass ich mich normalerweise nur mit englischer Lektüre auseinandersetze.

In der Methode "get_daysheet" erzeugst du ein neues DaySheet-Objekt, und gibst self.update_entry als Argument mit.
Du hast nun gefragt, ob da nun eine Kopie erstellt wird.
Die Antwort ist: Nein! Es gibt in Python kein "pass-by-value". Was dem Verhalten in Python am nahe kommt, ist "call-by-reference", das ist es aber auch nicht wirklich. Um es davon abzugrenzen wird es zum Teil als "pass-by-object" bezeichnet. Es wird also das Objekt als solches übergeben, das passiert in jedem Fall. Du könntest nun sagen, self.update_entry "zeigt" auf eine Methode, bzw ein Objekt (in diesem Fall nennt sich das Ding bound method, da es an eine Instanz gekoppelt ist(im_self)). Wenn du nun diese Methode als Parameter weitergibst, und dann bei einem anderen Objekt unter "self.update" (also bei einer DaySheet-Instanz) ablegst, so "zeigt" dieses Attribut "update" nun auf die ursprüngliche Methode "update_entry", welche sich auf das ursprüngliche Diary-Objekt bezieht.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

cofi hat geschrieben:Die Beiden sind Synonymk.
Ok. Wobei mir der Begriff 'Exemplar' passender als 'Instanz' erscheint. Zumindest im Deutschen.
cofi hat geschrieben:Wo ist da denn ein `daysheet.update`?
Wo? Na, 'update' ist ein Attribut des DaySheet-Exemplars, das auf die Diary()-Methode 'update_entry()' verweist... Ach so, Du meinst, meine Frage beantwortet sich selbst :wink: ? Na ja, jetzt, da ich die ganzen Infos von Euch bekommen hab' schon... :)
cofi hat geschrieben:... und kommt _nicht_ aus dem lexikalischen Scope.
Damit meinst Du das dict, in dem alle Attribute der Klasse drinstehen...?
Gibt es eigentlich ein gut gefülltes Nachschlagewerk, in dem sich diese vielen Begrifflichkeiten nachschlagen lassen?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

mutetella hat geschrieben:
cofi hat geschrieben:Wo ist da denn ein `daysheet.update`?
Wo? Na, 'update' ist ein Attribut des DaySheet-Exemplars, das auf die Diary()-Methode 'update_entry()' verweist...
Oh .. ich haette den Weg lieber ganz gehen sollen :( Hab nur das Attribut gesehen und falsche Schluesse gezogen.
mutetella hat geschrieben:
cofi hat geschrieben:... und kommt _nicht_ aus dem lexikalischen Scope.
Damit meinst Du das dict, in dem alle Attribute der Klasse drinstehen...?
Jein, der lexikalische Scope ist der textuelle "Rahmen", in dem ein Objekt steht. Das Methodenobjekt wiederum ist ein Closure ueber dem `self`, einfach gesagt: `method = partial(method, self)` bei der Erstellung eines Exemplars, wobei das `self` hier tatsaechlich das Exemplar ist.

Ein Detail noch damit du den konkreten Fall evtl besser verstehen kannst: `self.update_entry` wird schon vor der Exemplarerstellung aufgeloest, d.h. `DaySheet` bekommt eine "bound method" uebergeben.
mutetella hat geschrieben:Gibt es eigentlich ein gut gefülltes Nachschlagewerk, in dem sich diese vielen Begrifflichkeiten nachschlagen lassen?
Die englische Wikipedia, bei der deutschen bin ich mir nicht sicher ob sie die Anforderung "gut gefüllt" erfuellt bzw wie lange noch. Ansonsten noch das Glossar der Dokumentation
Antworten