2010-04-30 70 views
1

为了将各种类的方法放入全局注册表中,我使用了一个带有元类的装饰器。装饰器标签,元类将函数放入注册表中:python:子类的子类

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 

我现在已经到了需要两个函数注册表的地步。第一个想法是对元类进行子类化,并将其他注册表放入其中。为此,只需重写该方法即可。

由于重写意味着多余的代码,这不是我真正想要的。所以,如果有人能够说出如何将元素放在元类内部,那么当新的被执行时能够被读取,这将是很好的。有了这个正确的注册表可以放入,而不必重写新的

回答

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 
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或更早版本,你需要坚持瓦特/元类或明确的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 

所以,你可以这样做:

@RegisterExposedMethods 
class MyClass (object): 

    @ExposeMethod(WorkerFunctionRegistry) 
    def myCoolExposedMethod (self): 
     pass 

等。这很容易扩展到允许暴露的方法有多个注册表,从类中获取默认注册表(例如,它可以在类装饰器中,例如,如果它对您更好),可避免陷入元类而不会失去任何功能。事实上,正是为什么类装饰器是在Python 2.6中引入的:它们可以取代元类的90%左右的实际用途,并且比定制元类更简单。

+0

哇,这帮助了很多。但是,我从不希望将一个班的职能暴露给不同的登记处。我认为你和鲁珀的回答相结合的方式将符合我的需求。 而且,为了记录,我完全意识到这些方法是常规实例而不是静态方法:-)。我需要此注册表的原因是为了验证客户端请求的这种功能。如果函数在注册表中,则创建该实例并调用该方法。 – 2010-05-01 17:37:32

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()) 

随着亚历克斯的评论

你ExposedMethod情况下不表现为正常的实例方法...

不再是真实的,因为方法是简单的标记,而不是包装。