Frage

Ich möchte ein Python-Dekorateur in der Lage sein zu schaffen, die automatisch „Register“ Klassenmethoden in einem globalen Repository (mit einigen Eigenschaften).

Beispielcode:

class my_class(object):

    @register(prop1,prop2)
    def my_method( arg1,arg2 ):
       # method code here...

    @register(prop3,prop4)
    def my_other_method( arg1,arg2 ):
       # method code here...

Ich möchte, dass beim Laden fertig ist, irgendwo wird es eine dict sein enthalten:

{ "my_class.my_method"       : ( prop1, prop2 )
  "my_class.my_other_method" : ( prop3, prop4 ) }

Ist das möglich?

War es hilfreich?

Lösung

Nicht nur mit einem Dekorateur, nein. Aber ein Metaklasse kann automatisch mit einer Klasse arbeitet nach ihrer geschaffen. Wenn Ihr register Dekorateur macht nur Notizen über das, was die Metaklasse tun sollten, können Sie die folgenden Schritte ausführen:

registry = {}

class RegisteringType(type):
    def __init__(cls, name, bases, attrs):
        for key, val in attrs.iteritems():
            properties = getattr(val, 'register', None)
            if properties is not None:
                registry['%s.%s' % (name, key)] = properties

def register(*args):
    def decorator(f):
        f.register = tuple(args)
        return f
    return decorator

class MyClass(object):
    __metaclass__ = RegisteringType
    @register('prop1','prop2')
    def my_method( arg1,arg2 ):
        pass

    @register('prop3','prop4')
    def my_other_method( arg1,arg2 ):
        pass

print registry

Drucken

{'MyClass.my_other_method': ('prop3', 'prop4'), 'MyClass.my_method': ('prop1', 'prop2')}

Andere Tipps

Hier ist eine wenig Liebe für die Klasse Dekorateure. Ich denke, die Syntax ist etwas einfacher als die für metaclasses erforderlich.

def class_register(cls):
    cls._propdict = {}
    for methodname in dir(cls):
        method = getattr(cls, methodname)
        if hasattr(method, '_prop'):
            cls._propdict.update(
                {cls.__name__ + '.' + methodname: method._prop})
    return cls


def register(*args):
    def wrapper(func):
        func._prop = args
        return func
    return wrapper


@class_register
class MyClass(object):

    @register('prop1', 'prop2')
    def my_method(self, arg1, arg2):
        pass

    @register('prop3', 'prop4')
    def my_other_method(self, arg1, arg2):
        pass

myclass = MyClass()
print(myclass._propdict)
# {'MyClass.my_other_method': ('prop3', 'prop4'), 'MyClass.my_method': ('prop1', 'prop2')}

Wenn Sie den Klassen Namen benötigen, verwenden Matts Lösung. Wenn Sie jedoch ist ok mit nur die Methode Namen haben - oder einen Verweis auf das Verfahren - in der Registrierung, könnte dies einen einfacheren Weg, es zu tun sein:

class Registry:
    r = {}

    @classmethod
    def register(cls, *args):
        def decorator(fn):
            cls.r[fn.__name__] = args
            return fn
        return decorator

class MyClass(object):

    @Registry.register("prop1","prop2")
    def my_method( arg1,arg2 ):
        pass

    @Registry.register("prop3","prop4")
    def my_other_method( arg1,arg2 ):
        pass

print Registry.r

Drucken

{'my_other_method': ('prop3', 'prop4'), 'my_method': ('prop1', 'prop2')}

Nicht einfach, aber wenn Sie mit Python 3 sind dies sollte funktionieren:

registry = {}
class MetaRegistry(type):
    @classmethod
    def __prepare__(mcl, name, bases):
        def register(*props):
            def deco(f):
                registry[name + "." + f.__name__] = props
                return f
            return deco
        d = dict()
        d['register'] = register
        return d
    def __new__(mcl, name, bases, dct):
        del dct['register']
        cls = super().__new__(mcl, name, bases, dct)
        return cls

class my_class(object, metaclass=MetaRegistry):
    @register('prop1','prop2')
    def my_method( arg1,arg2 ):
       pass # method code here...

    @register('prop3','prop4')
    def my_other_method( arg1,arg2 ):
       pass # method code here...

print(registry)

Beachten Sie, dass Sie nicht Methodennamen gleich zu dem Dekoratornamens in der Meta-typisierte Klasse haben können, weil sie automatisch von dem del Befehl in der Metaklasse der __new__ Methode gelöscht werden.

Für Python 2.6 Ich denke, Sie explizit den Dekorateur die Klassennamen zu verwenden sagen müßten.

Nicht so schön oder elegant, aber wahrscheinlich der einfachste Weg, wenn Sie brauchen dies in einer Klasse nur:

_registry = {}
class MyClass(object):
    def register(*prop):
        def decorator(meth):
            _registry[MyClass.__name__ + '.' + meth.__name__] = prop
        return decorator

    @register('prop1', 'prop2')
    def my_method(self, arg1, arg2):
        pass
    @register('prop3', 'prop4')
    def my_other_method(self, arg1, arg2):
        pass

    del register

Nein. Der Dekorateur erhält die Funktion, bevor es eine Methode worden ist, so dass Sie nicht wissen, was Klasse ist es auf.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top