Python 元类与类装饰器
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!"
。
同样的道理适用于所有的魔法方法,也就是所有应用于类对象本身的操作(与应用于类的实例的操作不同,后者使用的是在类中定义的魔法方法 -- 而类对象本身的操作使用的是在元类中定义的魔法方法)。