为了将各种类的方法放入全局注册表中,我正在使用带有元类的装饰器。装饰器标签,元类将函数放在注册表中:
class ExposedMethod (object):
def __init__(self, decoratedFunction):
self._decoratedFunction = decoratedFunction
def __call__(__self,*__args,**__kw):
return __self._decoratedFunction(*__args,**__kw)
class ExposedMethodDecoratorMetaclass(type):
def __new__(mcs, name, bases, dct):
for obj_name, obj in dct.iteritems():
if isinstance(obj, ExposedMethod):
WorkerFunctionRegistry.addWorkerToWorkerFunction(obj_name, name)
return type.__new__(mcs, name, bases, dct)
class MyClass (object):
__metaclass__ = DiscoveryExposedMethodDecoratorMetaclass
@ExposeDiscoveryMethod
def myCoolExposedMethod (self):
pass
我现在已经到了需要两个功能注册表的地步。第一个想法是将元类子类化并将其他注册表放入其中。为此, new 方法只需要重写。
由于重写意味着冗余代码,这不是我真正想要的。因此,如果有人能够指定如何将属性放入元类中,并且在执行 new 时能够读取的属性,那将是很好的。有了这个,就可以放入正确的注册表,而无需重写 new 。
答案 0 :(得分:5)
你的ExposedMethod
个实例不像普通的实例方法那样行事,而是像静态方法一样 - 事实上你给其中一个self
个参数暗示你不知道这个。您可能需要向__get__
类添加ExposedMethod
方法以使其成为描述符,就像函数对象一样 - 有关描述符的更多信息,请参阅here。
但是有一种很多更简单的方法,因为函数可以有属性......:
def ExposedMethod(registry=None):
def decorate(f):
f.registry = registry
return f
return decorate
并且在一个类装饰器中(比元类更简单!需要Python 2.6或更高版本 - 在2.5或更早版本中,您需要坚持使用元类或在{{之后显式调用它) 1}}语句,虽然答案的第一部分和下面代码的功能仍然完美无缺):
class
所以你可以这样做:
def RegisterExposedMethods(cls):
for name, f in vars(cls).iteritems():
if not hasattr(f, 'registry'): continue
registry = f.registry
if registry is None:
registry = cls.registry
registry.register(name, cls.__name__)
return cls
之类的。这很容易扩展到允许暴露的方法有几个注册表,从类中获取默认注册表(它可以在类装饰器中,例如,如果这对你更好)和避免陷入与元类陷入困境而不会丢失任何功能。事实上,这正是Python 2.6中引入类装饰器的原因:它们可以代替90%左右的元类实际使用,并且比自定义元类更简单 。
答案 1 :(得分:0)
您可以使用class属性指向要在专用元类中使用的注册表,例如:
class ExposedMethodDecoratorMetaclassBase(type):
registry = None
def __new__(mcs, name, bases, dct):
for obj_name, obj in dct.items():
if isinstance(obj, ExposedMethod):
mcs.registry.register(obj_name, name)
return type.__new__(mcs, name, bases, dct)
class WorkerExposedMethodDecoratorMetaclass(ExposedMethodDecoratorMetaclassBase):
registry = WorkerFunctionRegistry
class RetiredExposedMethodDecoratorMetaclass(ExposedMethodDecoratorMetaclassBase):
registry = RetiredFunctionRegistry
答案 2 :(得分:0)
谢谢你们的回答。两者都帮助我找到了适合我的请求的方法。
我对此问题的最终解决方案如下:
def ExposedMethod(decoratedFunction):
decoratedFunction.isExposed = True
return decoratedFunction
class RegisterExposedMethods (object):
def __init__(self, decoratedClass, registry):
self._decoratedClass = decoratedClass
for name, f in vars(self._decoratedClass).iteritems():
if hasattr(f, "isExposed"):
registry.addComponentClassToComponentFunction(name, self._decoratedClass.__name__)
# cloak us as the original class
self.__class__.__name__ = decoratedClass.__name__
def __call__(self,*__args,**__kw):
return self._decoratedClass(*__args,**__kw)
def __getattr__(self, name):
return getattr(self._decoratedClass, name)
在课堂上我希望公开方法,我会做以下事情:
@RegisterExposedMethods
class MyClass (object):
@ExposedMethod
def myCoolExposedMethod (self):
pass
类装饰器现在很容易被子类化。这是一个例子:
class DiscoveryRegisterExposedMethods (RegisterExposedMethods):
def __init__(self, decoratedClass):
RegisterExposedMethods.__init__(self,
decoratedClass,
DiscoveryFunctionRegistry())
有了Alex的评论
您的ExposedMethod实例不像普通实例方法那样......
不再是真的,因为该方法只是被标记并且没有被包装。