Wenn Sie eine Methode dekorieren, ist sie noch nicht an die Klasse gebunden und verfügt daher noch nicht über das Attribut im_class. Ich suche nach einer Möglichkeit, die Informationen über die Klasse im Dekorateur zu erhalten. Ich habe es versucht:

import types

def decorator(method):

    def set_signal(self, name, value):
        print name
        if name == 'im_class':
            print "I got the class"

    method.__setattr__ = types.MethodType(set_signal, method)

    return method


class Test(object):
    @decorator
    def bar(self, foo):
        print foo

Aber es druckt nichts.

Ich kann mir das vorstellen:

class Test(object):
    @decorator(klass=Test)
    def bar(self, foo):
        print foo

Aber wenn ich es vermeiden kann, würde es meinen Tag machen.

4
e-satis 8 Okt. 2012 im 13:08

3 Antworten

Meine strenge Antwort wäre: Es ist nicht möglich, da die Klasse noch nicht existiert, wenn der Dekorateur ausgeführt wird.

Die längere Antwort hängt von Ihren genauen Anforderungen ab. Wie ich geschrieben habe, können Sie nicht auf die Klasse zugreifen, wenn sie noch nicht existiert. Eine Lösung wäre, die dekorierte Methode zu markieren, die später "transformiert" werden soll. Verwenden Sie dann eine Metaklasse oder einen Klassendekorateur, um Ihre Änderungen anzuwenden, nachdem die Klasse erstellt wurde.

Eine andere Option beinhaltet etwas Magie. Suchen Sie nach der Implementierung der Methode implements in zope.interfaces. Es hat Zugriff auf die Informationen über die Klasse, die gerade analysiert wurde. Ich weiß nicht, ob es für Ihren Anwendungsfall ausreicht.

1
Achim 8 Okt. 2012 im 09:40

Verwenden Sie Methodendekoratoren, um den interessanten Methoden einige Markierungsattribute hinzuzufügen, und verwenden Sie eine Metaklasse, die die Methoden durchläuft, die Markierungsattribute findet und die Logik ausführt. Der Metaklassencode wird beim Erstellen der Klasse ausgeführt, sodass er auf die neu erstellte Klasse verweist.

class MyMeta(object):
  def __new__(...):
    ...
    cls = ...
    ... iterate over dir(cls), find methods having .is_decorated, act on them
    return cls
def decorator(f):
  f.is_decorated = True
  return f
class MyBase(object):
  __metaclass__ = MyMeta
class MyClass(MyBase):
  @decorator
  def bar(self, foo):
    print foo

Wenn Sie sich darüber Sorgen machen, dass der Programmierer von MyClass die Verwendung von MyBase vergisst, können Sie die Metaklasse zwangsweise in decorator setzen, indem Sie das globale Wörterbuch des Aufrufer-Stack-Frames ({{X3}) untersuchen. }).

0
pts 8 Okt. 2012 im 09:50

Vielleicht möchten Sie einen Blick auf Deskriptoren werfen. Mit ihnen können Sie ein __get__ implementieren, das beim Zugriff auf ein Attribut verwendet wird, und können je nach Objekt und Typ verschiedene Dinge zurückgeben.

0
madjar 8 Okt. 2012 im 09:30