Python元类与类装饰器

时间:2009-11-22 17:39:40

标签: python decorator metaclass

Python元类和类装饰器之间的主要区别是什么?有什么我可以用一个而不用另一个吗?

2 个答案:

答案 0 :(得分:40)

装饰器更简单,更简单,更有限 - 因此,只要使用元类或类装饰器可以实现所需的效果,它就应该是首选。

你可以用类装饰器做任何事情,你当然可以使用自定义元类(只需应用“装饰器函数”的功能,即采用类对象并修改它的那个,在过程中创建类对象的元类__new____init__! - 。

你可以在自定义元类中做很多事情但不能在装饰器中做(除非装饰器内部生成并应用自定义元类,当然 - 但这是作弊; - )......甚至在Python中也是如此3,有些东西只能用自定义元类来实现,而不是事后......但这是你问题的一个非常先进的小生境,所以让我给出更简单的例子。)

例如,假设您要创建一个类对象X,使print X(或在Python 3中print(X)当然;-)显示peekaboo!。没有自定义元类,你不可能做到这一点,因为元类的覆盖__str__是这里的关键角色,即你需要在类def __str__(cls): return "peekaboo!"的自定义元类中使用X

这同样适用于所有魔术方法,即应用于类对象本身的所有类型的操作(相对于应用于其实例的操作,使用其中定义的魔术方法)类 - 类对象本身的操作使用元类中定义的魔术方法。

答案 1 :(得分:1)

正如“流利的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

脚本使用元类替换/覆盖方法'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