元混合或链接

时间:2014-11-20 08:46:06

标签: python metaprogramming decorator metaclass python-decorators

考虑一下代码:

class Meta(type):
    def __init__(cls, name, bases, attrs):
        def method(self):
            print('generated method call')
        cls.method = method
        super(Meta, cls).__init__(name, bases, attrs)


class A(object):
    __metaclass__ = Meta

    def method(self):
        raise NotImplementedError


def decorator(fn):
    def wrapper(*args, **kwargs):
        print('decorator call')
        return fn(*args, **kwargs)

    return wrapper

class Decorator(object):
    """Mysterious mixin that should wrap `method` with `decorator`
    at class generation time. And this effect should work on subclasses too!
    """
    def __call__(self, cls):
        cls.method = decorator(cls.method)
        return cls

@Decorator()
class B(A):
    pass

B().method() # outputs "decorated call generated method call"

class D(B):
    pass

D().method() # outputs only "generated method call"

这里我有一个基类A,它有一个生成method的元类。 比我有Decorator类装饰器,它会对装饰类的method产生一些影响。

它在装饰类B上完美运行,但其效果不可继承,因此D不会继承该效果。

这就是我想要实现的目标 - 学习如何创建可继承的类装饰器。或者它可以被称为元类混合。

如何实现这种效果?我对元类的所有尝试均因metaclass conflict错误而失败。

1 个答案:

答案 0 :(得分:0)

BD这两个类都有自己对method的引用。这是因为您每次创建新课程时都会在Meta __init__方法中进行分配。您可以通过查看__dict__属性(例如print(D.__dict__))来查看。

要实现继承行为,类D不能包含自己的method,这样它将从父类B中获取method装饰。

从上述说法中我提出以下解决方案:

def decorator(cls):
    def _dec(original_method):
        def _method(*args, **kwargs):
            print('{cls_name} decorated: '.format(cls_name=cls.__name__), end='')
            return original_method(*args, **kwargs)
        return _method
    cls.method = _dec(cls.method)
    return cls


class A():

    def method(self):
        pass


@decorator
class B(A):
    pass


class D(B):
    pass

if __name__ == '__main__':
    A().method() or print('A')
    B().method() or print('B')
    D().method() or print('D')

执行此代码的结果如下:

A
B decorated: B
B decorated: D