27

クラスメソッドをグローバルリポジトリに自動的に「登録」するPythonデコレータを作成できるようにしたいと考えています(いくつかのプロパティを使用)。

コード例:

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...

ロードが完了すると、どこかに次を含むdictがあることを望みます:

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

これは可能ですか?

4

7 に答える 7

23

クラスデコレータへのちょっとした愛があります。構文は、メタクラスに必要な構文よりも少し単純だと思います。

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')}
于 2010-06-16T15:52:10.043 に答える
18

デコレータだけではありません。しかし、メタクラスは、クラスが作成された後、自動的にクラスを操作できます。デコレータがメタクラスが何をすべきかについてメモを作成するだけの場合registerは、次のことができます。

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

印刷

{'MyClass.my_other_method': ('prop3', 'prop4'), 'MyClass.my_method': ('prop1', 'prop2')}
于 2010-06-16T15:00:52.613 に答える
8

クラス名が必要な場合は、Matt のソリューションを使用してください。ただし、メソッド名 (またはメソッドへの参照) をレジストリに保持するだけで問題ない場合は、次の方法の方が簡単な場合があります。

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

印刷する

{'my_other_method': ('prop3', 'prop4'), 'my_method': ('prop1', 'prop2')}
于 2012-10-26T14:18:50.183 に答える
5

美しくもエレガントでもありませんが、これが 1 つのクラスでのみ必要な場合は、おそらく最も簡単な方法です。

_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
于 2010-06-16T16:18:54.187 に答える
3

簡単ではありませんが、Python 3 を使用している場合、これでうまくいくはずです:

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)

delメソッド名は、メタクラスのメソッド内のコマンドによって自動的に削除されるため、メタ型付きクラスのデコレーター名と同じにすることはできないことに注意してください__new__

Python 2.6 の場合、デコレータに使用するクラス名を明示的に伝える必要があると思います。

于 2010-06-16T14:59:49.247 に答える
-1

いいえ。デコレータは関数がメソッドになる前に関数を受け取るため、関数がどのクラスにあるのかわかりません。

于 2010-06-16T14:50:33.103 に答える