2009-07-15 3 views
0

Derzeit mache ich es auf diese Weise:einen Dekorateur in einer Klasse mit Zugang zur (aktuellen) Klasse Erstellen selbst

class Spam(object): 

    decorated = None 

    @classmethod 
    def decorate(cls, funct): 
     if cls.decorated is None: 
      cls.decorated = [] 
     cls.decorated.append(funct) 
     return funct 


class Eggs(Spam): 
    pass 


@Eggs.decorate 
def foo(): 
    print "spam and eggs" 


print Eggs.decorated # [<function foo at 0x...>] 
print Spam.decorated # None 

ich Notwendigkeit Lage sein, dies in einer Unterklasse zu tun, wie gezeigt. Das Problem ist, dass ich nicht herausfinden kann, wie man das decorated Feld, das zwischen Instanzen nicht geteilt wird, macht. Im Moment habe ich eine hackische Lösung, indem ich es zunächst auf None setze und dann überprüfe, wenn die Funktion eingerichtet ist, aber das funktioniert nur in einer Richtung. Mit anderen Worten, wenn ich Eggs unterwerfe und dann etwas mit der Eggs.decorate Funktion dekoriere, betrifft dies alle Unterklassen.

Ich denke, meine Frage ist: ist es möglich, muable Klassenfelder haben, die nicht zwischen Basis-und Unterklassen geteilt werden?

+0

Nur aus Neugier: Warum müssen Sie im Auge behalten, welche Funktionen eingerichtet wurden? –

+0

Gute Frage. Ich tue das eigentlich nicht, aber ich habe dieses Szenario als Beispiel für diese Frage entwickelt, weil es ein einfacher Grund ist, auf die Klasse zugreifen zu müssen. –

Antwort

1

ich es herausgefunden durch metaclasses verwenden. Danke für alle, die gepostet haben. Hier ist meine Lösung, wenn jemand über ein ähnliches Problem kommt:

class SpamMeta(type): 

    def __new__(cls, name, bases, dct): 
     SpamType = type.__new__(cls, name, bases, dct) 
     SpamType.decorated = [] 
     return SpamType 


class Spam(object): 

    __metaclass__ = SpamMeta 

    @classmethod 
    def decorate(cls, funct): 
     cls.decorated.append(funct) 
     return funct 


class Eggs(Spam): 
    pass 


@Eggs.decorate 
def foo(): 
    print "spam and eggs" 


print Eggs.decorated # [<function foo at 0x...>] 
print Spam.decorated # [] 
0

Ich bin mir ziemlich sicher, dass Sie nicht können. Ich habe darüber nachgedacht, dies mit property() zu tun, aber leider ist die Klasse der Klasse selbst - wo eine Eigenschaft gehen müsste - ClassType selbst.

Sie können Ihren Dekorateur so schreiben, aber es ändert sich die Schnittstelle ein wenig:

class Spam(object): 
    decorated = {} 

    @classmethod 
    def get_decorated_methods(cls): 
     return cls.decorated.setdefault(cls, []) 

    @classmethod 
    def decorate(cls, funct): 
     cls.get_decorated_methods().append(funct) 
     return funct 


class Eggs(Spam): 
    pass 


@Spam.decorate 
def foo_and_spam(): 
    print "spam" 

@Eggs.decorate 
def foo_and_eggs(): 
    print "eggs" 

print Eggs.get_decorated_methods() # [<function foo_and_eggs at 0x...>] 
print Spam.get_decorated_methods() # [<function foo_and_spam at 0x...>] 
+0

Ich habe es perfekt mit der Verwendung von Metaklassen funktionieren. Ich habe die Antwort veröffentlicht, wenn Sie neugierig sind, wie. Danke für die Untersuchung, Glenn. –

0

Nicht, dass ich etwas gegen metaclasses haben, aber man kann es auch ohne sie lösen:

from collections import defaultdict 

class Spam(object): 
    _decorated = defaultdict(list) 

    @classmethod 
    def decorate(cls, func): 
     cls._decorated[cls].append(func) 
     return func 

    @classmethod 
    def decorated(cls): 
     return cls._decorated[cls] 


class Eggs(Spam): 
    pass 

@Eggs.decorate 
def foo(): 
    print "spam and eggs" 

print Eggs.decorated() # [<function foo at 0x...>] 
print Spam.decorated() # [] 

Es ist nicht möglich, Eigenschaften zu haben Bei Klassenobjekten (es sei denn, Sie kehren wieder zu Metaklassen zurück), ist es zwingend erforderlich, die Liste der dekorierten Methoden erneut über eine Klassenmethode zu erhalten. Im Vergleich zur Metaklassenlösung gibt es eine zusätzliche Indirektionsebene.

+0

Ja, das scheint ähnlich wie Glenn zu sein. Obwohl es für dieses Beispiel funktioniert, löst es immer noch nicht das Problem, dass ich nicht wollte, dass Klassenfelder zwischen Eltern und Kindern geteilt werden. –

Verwandte Themen