2 Stimmen

Erkennen, ob super() eine Funktion mit Dekorator hat?

Ich definiere mehrere Klassen, die für die Mehrfachvererbung verwendet werden sollen, z. B.:

class A:
    def __init__(self, bacon = None, **kwargs):
        self.bacon = bacon
        if bacon is None:
            self.bacon = 100
        super().__init__(**kwargs)
class Bacon(A):
    def __init__(self, **kwargs):
        """Optional: bacon"""
        super().__init__(**kwargs)

class Eggs(A):
    def __init__(self, **kwargs):
        """Optional: bacon"""
        super().__init__(**kwargs)

class Spam(Eggs, Bacon):
    def __init__(self, **kwargs):
        """Optional: bacon"""
        super().__init__(**kwargs)

Ich habe jedoch mehrere Klassen (z. B. möglicherweise Bacon , A y Spam , aber nicht Eggs ), die sich darum kümmern, wann ihr Eigentum bacon geändert wird. Sie brauchen den Wert nicht zu ändern, sondern nur zu wissen, wie der neue Wert lautet, wie ein Ereignis. Aufgrund der Mehrfachvererbung, die ich eingerichtet habe, würde dies bedeuten, dass die Superklasse über die Änderung benachrichtigt werden muss (sofern sie sich dafür interessiert).

Ich weiß, dass es möglich sein könnte, wenn ich den Klassennamen an den Methodendekorator übergebe oder wenn ich einen Klassendekorator verwende. Ich möchte nicht die ganze direkte Selbst-Klassen-Referenzierung haben, viele Dekoratoren über jeder Klasse erstellen müssen, oder die Methoden zwingen, den gleichen Namen zu haben, da nichts davon sehr pythonisch klingt.

Ich hatte gehofft, eine Syntax zu erhalten, die in etwa so aussieht:

    @on_change(bacon)
    def on_bacon_change(self, bacon):
        # read from old/new bacon
        make_eggs(how_much = bacon)

Mir ist der vorherige Wert von bacon so dass das Speck-Argument nicht notwendig ist, wenn es nach bacon eingestellt ist.

  • Ist es möglich, zu prüfen, ob eine Superklasse eine Methode mit dieser Dekator hat?

  • Wenn dies nicht möglich ist, gibt es Alternativen zur Weitergabe von Ereignissen wie durch die Kette der Mehrfachvererbung weiterzugeben?

EDITAR:

Der eigentliche Aufruf der Funktion in Spam würde in A erfolgen, indem man eine @property y @bacon.setter da dies die oberste Klasse sein würde, die die bacon . Sobald es weiß, welche Funktion es aufzurufen hat self liegt das Problem nur in der Weiterleitung des Aufrufs in der MI-Kette.

EDIT 2:

Überschreibe ich das Attribut mit einer @bacon.setter Wäre es möglich, festzustellen, ob die Klasse super() einen Setter für bacon ?

2voto

jsbueno Punkte 84804

Was Sie fordern, würde wahrscheinlich gut in einen umfassenderen Rahmen von Signalen und so weiter passen - vielleicht sogar zu Aspected Oriented Programing einladen.

Ohne in die Tiefe zu gehen, können eine Metaklasse und ein Dekorator genau das tun, wonach Sie fragen - ich habe mir diese ausgedacht, ich hoffe, sie funktionieren für Sie.

Wenn Sie dies zu etwas Robustem und Brauchbarem weiterentwickeln möchten, schreiben Sie mir - wenn es nichts dergleichen gibt, wäre es lohnenswert, ein Hilfspaket dafür in pipy zu haben.

def setattr_wrapper(cls):
    def watcher_setattr(self, attr, val):
        super(cls, self).__setattr__(attr, val)
        watched = cls.__dict__["_watched_attrs"]
        if attr in watched:
            for method in watched[attr]:
                getattr(self, method)(attr, val)
    return watcher_setattr

class AttrNotifier(type):
    def __new__(metacls, name, bases, dct):
        dct["_watched_attrs"] = {}
        for key, value in dct.items():
            if hasattr(value, "_watched_attrs"):
                for attr in getattr(value, "_watched_attrs"):
                    if not attr in dct["_watched_attrs"]:
                        dct["_watched_attrs"][attr] = set()
                    dct["_watched_attrs"][attr].add(key)
        cls = type.__new__(metacls, name, bases, dct)
        cls.__setattr__ = setattr_wrapper(cls)
        return cls

def on_change(*args):
    def decorator(meth):
        our_args = args
        #ensure that this decorator is stackable
        if hasattr(meth, "_watched_attrs"):
            our_args = getattr(meth, "_watched_attrs") + our_args
        setattr(meth, "_watched_attrs", our_args)
        return meth
    return decorator

# from here on, example of use:
class A(metaclass=AttrNotifier):
    @on_change("bacon")
    def bacon_changed(self, attr, val):
        print ("%s changed in %s to %s" % (attr, self.__class__.__name__, val)) 

class Spam(A):
    @on_change("bacon", "pepper")
    def changed(self, attr, val):
        print ("%s changed in %s to %s" % (attr, self.__class__.__name__, val)) 

a = A()
a.bacon = 5

b = Spam()
b.pepper = 10
b.bacon = 20

(getestet in Python 3.2 und Python 2.6 - Änderung der Deklaration der Klasse "A" für Python 2 Metaklassen-Syntax)

edit - einige Worte dazu, was getan wird Das geschieht folgendermaßen: Die Metaklasse wählt alle Methoden aus, die mit dem "on_close"-Dekorator markiert sind, und registriert sie in einem Wörterbuch der Klasse - dieses Wörterbuch heißt _watched_attrs und es kann wie ein normales Klassenattribut aufgerufen werden.

Die andere Sache, die die Metaklasse tut, ist die Überschreibung der __setattr__ Methode für die Klasse, sobald sie erstellt ist. Diese neue __setattr__ setzt nur das Attribut, und prüft dann die _wacthed_attrs ob es in dieser Klasse Methoden gibt, die registriert sind, um aufgerufen zu werden, wenn das gerade geänderte Attribut geändert wurde - wenn ja, werden sie aufgerufen.

Die zusätzliche Indirektionsebene um watcher_setattr (das ist die Funktion, die für jede Klasse die __setattr__ ist dazu da, damit Sie für jede Klasse in der Vererbungskette verschiedene Attribute registrieren können, die überwacht werden sollen - alle Klassen haben unabhängig voneinander zugängliche _watched_attrs Wörterbücher. Wäre dies nicht der Fall, würde nur die am meisten spezifizierte Klasse in der Vererbungskette _watched_attrs respektiert werden würde.

0voto

ninjagecko Punkte 82995

Sie suchen nach python Eigenschaften :

http://docs.python.org/library/functions.html#property

Suchen Sie bei Google nach override superclass property setter führte zu dieser StackOverflow-Frage:

Überschreiben der Getter und Setter von geerbten Eigenschaften in Python

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X