Python 元类与类装饰器

发布于 2024-08-12 06:17:11 字数 59 浏览 6 评论 0原文

Python 元类和类装饰器之间的主要区别是什么?有什么事情我可以用其中一个来做,但不能用另一个来做吗?

What are the main differences between Python metaclasses and class decorators? Is there something I can do with one but not with the other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情话墙 2024-08-19 06:17:11

装饰器要简单得多,也更受限制——因此,只要可以使用元类或类装饰器实现所需的效果,装饰器就应该是首选。

您可以使用类装饰器执行的任何操作,当然也可以使用自定义元类执行(只需应用“装饰器函数”的功能,即在元类的 < 过程中采用类对象并修改它的功能) code>__new__ 或 __init__ 生成类对象!-)。

你可以在自定义元类中做很多事情,但不能在装饰器中做(当然,除非装饰器在内部生成并应用自定义元类 - 但这是作弊;-)...即使如此,在 Python 3 中,也有这些事情你只能用自定义元类来做,而不是事后做……但这是你的问题的一个相当高级的子领域,所以让我给出更简单的例子)。

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

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

Decorators are much, much simpler and more limited -- and therefore should be preferred whenever the desired effect can be achieved with either a metaclass or a class decorator.

Anything you can do with a class decorator, you can of course do with a custom metaclass (just apply the functionality of the "decorator function", i.e., the one that takes a class object and modifies it, in the course of the metaclass's __new__ or __init__ that make the class object!-).

There are many things you can do in a custom metaclass but not in a decorator (unless the decorator internally generates and applies a custom metaclass, of course -- but that's cheating;-)... and even then, in Python 3, there are things you can only do with a custom metaclass, not after the fact... but that's a pretty advanced sub-niche of your question, so let me give simpler examples).

For example, suppose you want to make a class object X such that print X (or in Python 3 print(X) of course;-) displays peekaboo!. You cannot possibly do that without a custom metaclass, because the metaclass's override of __str__ is the crucial actor here, i.e., you need a def __str__(cls): return "peekaboo!" in the custom metaclass of class X.

The same applies to all magic methods, i.e., to all kinds of operations as applied to the class object itself (as opposed to, ones applied to its instances, which use magic methods as defined in the class -- operations on the class object itself use magic methods as defined in the metaclass).

掀纱窥君容 2024-08-19 06:17:11

正如《Fluent Python》一书第 21 章所述,其中一个区别与继承有关。请看这两个脚本。 python版本是3.5。一点是,元类的使用会影响其子类,而装饰器仅影响当前类。

该脚本使用类装饰器来替换/覆盖方法“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

As given in the chapter 21 of the book 'fluent python', one difference is related to inheritance. Please see these two scripts. The python version is 3.5. One point is that the use of metaclass affects its children while the decorator affects only the current class.

The script use class-decorator to replace/overwirte the method '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

The script use metaclass to replace/overwrite the method '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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文