Python 元类与类装饰器

45 投票
2 回答
10911 浏览
提问于 2025-04-15 16:16

Python中的元类和类装饰器有什么主要区别?有没有什么是我可以用其中一个做,但另一个做不到的?

2 个回答

4

在《流畅的Python》这本书的第21章中提到,一个区别和继承有关。请看这两个脚本。这里使用的是Python 3.5版本。一个要点是,使用metaclass会影响到它的子类,而装饰器只影响当前的类。

这个脚本使用类装饰器来替换或覆盖方法'func1'。

def deco4cls(cls):
    cls.func1 = lambda self: 2
    return cls


@deco4cls
class Cls1:
    pass


class Cls1_1(Cls1):
    def func1(self):
        return 3


obj1_1 = Cls1_1()
print(obj1_1.func1())  # 3

这个脚本使用metaclass来替换或覆盖方法'func1'。

class Deco4cls(type):
    def __init__(cls, name, bases, attr_dict):
        # print(cls, name, bases, attr_dict)
        super().__init__(name, bases, attr_dict)
        cls.func1 = lambda self: 2


class Cls2(metaclass=Deco4cls):
    pass


class Cls2_1(Cls2):
    def func1(self):
        return 3


obj2_1 = Cls2_1()
print(obj2_1.func1())  # 2!! the original Cls2_1.func1 is replaced by metaclass
49

装饰器其实简单得多,而且功能也有限,所以在你能用装饰器或者元类实现同样效果的时候,建议优先使用装饰器。

你用装饰器能做到的事情,当然也可以用自定义的元类来实现(只要在元类的 __new____init__ 方法中应用“装饰器函数”的功能,也就是那个会修改类对象的函数)。

在自定义元类中,你可以做很多装饰器做不到的事情(除非装饰器内部生成并应用了一个自定义的元类,不过那样就有点作弊了;-)...即使这样,在 Python 3 中,有些事情只有用自定义元类才能做到,而不能在之后再处理...不过这属于比较高级的内容,咱们先来看一些简单的例子。

比如,假设你想创建一个类对象 X,让 print X(在 Python 3 中是 print(X))输出 peekaboo!。你必须使用自定义元类才能做到这一点,因为元类重写的 __str__ 方法是关键,也就是说,你需要在类 X 的自定义元类中写一个 def __str__(cls): return "peekaboo!"

同样的道理适用于所有的魔法方法,也就是所有应用于类对象本身的操作(与应用于类的实例的操作不同,后者使用的是在类中定义的魔法方法 -- 而类对象本身的操作使用的是在元类中定义的魔法方法)。

撰写回答