Handler je nach Klasse

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
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Hallo,
ich möchte für ein kleines Pluginsystem verschiedene Handler für meine Programme ermöglichen. Ich habe eine Grundklasse, von der jede Klasse meines Programms (Product, Transaction, etc.) abgeleitet wird.

Diese ist im Konkreten so aufgebaut:

Code: Alles auswählen

class CPClass(object):
    id = None
    actions = {"init": []}
    
    @reconstructor
    def __init__(self,**kwargs):
        for key,value in kwargs.iteritems():
            setattr(self,key,value)
    
    @hybrid_method
    def search(cls,condition=None,**kwargs):
        if condition:
            return session.query(cls).filter(condition)
        else:
            return session.query(cls).filter_by(**kwargs)
    
    @hybrid_method
    def search_one(cls,condition=None,**kwargs):
        return cls.search(condition=condition,**kwargs).one()
    
    @classmethod
    def on(cls,action,handler):
        try:
            cls.actions[action].append(handler)
        except KeyError:
            cls.actions[action] = list()
            cls.actions[action].append(handler)
Die abgeleiteten Klassen werden dann ebenso von "Base" aus Sqlalchemy abgeleitet. Das Ganze funktioniert soweit ganz gut.
Nun habe ich aber das Problem, dass wenn ich zum Beispiel auf das abgeleitete "Transaction" mittels on einen Handler registriere, dieser für alle anderen Klassen ebenso registriert ist, nicht nur für Transaction. Nach meiner Auffassung müsste das ja dann nur in Transaction.actions abgespeichert werden, wird so nun aber in CPClass.actions hinterlegt.

Wo habe ich da meinen Denkfehler?

Vielen Dank.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Ja, du hast da einen Denkfehler:

Code: Alles auswählen

>>> class Base(object):
...     actions = []
... 
>>> class Spam(Base): pass
... 
>>> class Eggs(Base): pass
... 
>>> id(Base.actions)
140671944032408
>>> id(Spam.actions)
140671944032408
>>> id(Eggs.actions)
140671944032408
Alle Klassen teilen sich "actions". Wenn du ein actions-Attribute pro Klasse willst, dann musst du dies auch explizit erstellen.

Edit: Und schau dir mal ``collections.defaultdict`` an, damit wird die on-Funktion zu einem Einzeiler.
Das Leben ist wie ein Tennisball.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

Vielen Dank, das war mir so nicht bewusst :-) Sehe ich es also richtig, dass ich die on-Methode behalten kann, aber dafür actions jedes Mal explizit festlegen muss?
Sirius3
User
Beiträge: 18318
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie kommst Du auf die Idee, dass auf magische Weise das Attribut »CPClass.actions« nach »Transaction.actions« wandert? Es wird einmal beim Erstellen der Klasse »CPClass« erzeugt und ihm ein Dictionary (was besser wohl ein »collections.defaultdict« wäre) zugewiesen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

sprudel hat geschrieben:Sehe ich es also richtig, dass ich die on-Methode behalten kann, aber dafür actions jedes Mal explizit festlegen muss?
Wenn ich dich richtig verstanden habe, dann ja.
Das Leben ist wie ein Tennisball.
sprudel
User
Beiträge: 250
Registriert: Donnerstag 8. März 2007, 17:12

War wohl eine grundsätzliche Verständnisfrage, ich betrachtete das Ableiten (vererben) im Grunde nur als eine Kopie der Ursprungsklasse, im Grunde nur eine 1:1-Kopie des Programmcodes. Verstehst du wie ich meine?
BlackJack

@sprudel: Nur das es eben keine Kopie ist. Das wäre auch etwas unökonomisch Kopien zu erzeugen die dann ja gleich sind, statt das bereits vorhandene zu verwenden.
Antworten