ada*_*amk 17 python oop design-patterns metaclass decorator
我希望能够创建一个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...
Run Code Online (Sandbox Code Playgroud)
我希望在加载完成时,某个地方会有一个dict包含:
{ "my_class.my_method" : ( prop1, prop2 )
"my_class.my_other_method" : ( prop3, prop4 ) }
Run Code Online (Sandbox Code Playgroud)
这可能吗?
Mat*_*son 17
不只是一个装饰,不.但是一个元类在创建后可以自动使用它.如果您的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
Run Code Online (Sandbox Code Playgroud)
印花
{'MyClass.my_other_method': ('prop3', 'prop4'), 'MyClass.my_method': ('prop1', 'prop2')}
Run Code Online (Sandbox Code Playgroud)
unu*_*tbu 15
这是对类装饰者的一点爱.我认为语法比元类所需的语法稍微简单一些.
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')}
Run Code Online (Sandbox Code Playgroud)
如果您需要类名,请使用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
Run Code Online (Sandbox Code Playgroud)
打印
{'my_other_method': ('prop3', 'prop4'), 'my_method': ('prop1', 'prop2')}
Run Code Online (Sandbox Code Playgroud)
要总结、更新和解释现有答案,您有两种选择:
然而,它们都依赖于为函数提供一个属性,以便可以识别它:
def register(*args):
"""
Creates an attribute on the method, so it can
be discovered by the metaclass
"""
def decorator(f):
f._register = args
return f
return decorator
Run Code Online (Sandbox Code Playgroud)
def register(*args):
"""
Creates an attribute on the method, so it can
be discovered by the metaclass
"""
def decorator(f):
f._register = args
return f
return decorator
Run Code Online (Sandbox Code Playgroud)
import inspect
def class_register(cls):
for method_name, _ in inspect.getmembers(cls):
method = getattr(cls, method_name)
if hasattr(method, "_prop"):
cls._propdict.update({f"{cls.__name__}.{method_name}": method._prop})
return cls
@class_register
class MyClass:
_propdict = {}
@register("prop1", "prop2")
def my_method(self, arg1, arg2):
pass
@register("prop3", "prop4")
def my_other_method(self, arg1, arg2):
pass
print(MyClass._propdict)
Run Code Online (Sandbox Code Playgroud)
不那么漂亮或优雅,但如果您只需要在一个班级中使用它,这可能是最简单的方法:
_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
Run Code Online (Sandbox Code Playgroud)