python:元类的子类

2024-04-23 09:11:34 发布

您现在位置:Python中文网/ 问答频道 /正文

为了将各种类的方法放入全局注册表中,我使用了一个带元类的decorator。decorator标记,元类将函数放入注册表中:

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的情况下放入正确的注册表。在


Tags: 方法函数nameselfobjnewobject注册表
3条回答

可以使用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

您的ExposedMethod实例的行为不像普通的实例方法,而是类似于静态方法——事实上,您给其中一个实例一个self参数提示您并不知道这一点。您可能需要将__get__方法添加到ExposedMethod类中,使其成为描述符,就像函数对象有关描述符的更多信息,请参见here。在

但是有一种更简单的方法,因为函数可以有属性…:

def ExposedMethod(registry=None):
    def decorate(f):
        f.registry = registry
        return f
    return decorate

在一个修饰符中(比元类简单!需要Python2.6或更高版本的2.5或更早版本您需要使用元类或在class语句后显式地调用它,尽管答案的第一部分和下面代码的功能仍然很好):

^{2}$

所以你可以:

@RegisterExposedMethods
class MyClass (object):

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

诸如此类。这很容易扩展到允许一个公开的方法有多个注册中心,从其他地方而不是从类中获取默认注册表(它可以在类修饰符中,例如,如果这对您更有效的话)避免与元类结合而不丢失任何功能。实际上,这正是Python2.6中引入类装饰器的原因:它们可以代替大约90%的元类实际使用,并且比自定义元类简单得多。在

谢谢你们的回答。两人都帮助我找到了一个合适的方法来满足我的要求。在

我对这个问题的最终解决办法是:

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)

对于要从中公开方法的类,我执行以下操作:

^{2}$

类装饰器现在很容易被子类化。下面是一个例子:

class DiscoveryRegisterExposedMethods (RegisterExposedMethods):
    def __init__(self, decoratedClass):
        RegisterExposedMethods.__init__(self,
                                        decoratedClass,
                                        DiscoveryFunctionRegistry())

亚历克斯的评论是这么说的

Your ExposedMethod instances do not behave as normal instance methods ...

不再是真的,因为方法只是被标记而不是包装。在

相关问题 更多 >