什么是Python元类有用?

Jua*_*nti 30 python metaclass class decorator

对于不能以任何其他方式使用的元类,可以做些什么?

亚力理马尔泰利说,如果没有元类,这里有一些任务无法实现Python元类和类装饰器 我想知道哪些是?

Ale*_*lli 19

如果你想要具有"特殊定制行为"的类对象(而不是类对象的实例),元类是必不可少的,因为对象的行为取决于对象类型的特殊方法,而类对象的类型是,元类的同义词.

例如,如果你想要一个类对象X,使得"print X"发出"时间现在是早上8:46"(上午8:46,或者更一般地说,是当前时间),这必然意味着type(x)(AKA X的元类)有一个特殊的自定义__str__方法 - 并且类似地(使用各种适用的特殊方法)如果你想给表达式赋予意义,例如X + YX和Y都是类对象,或者X[23](其中X,同样是一个类对象),等等.

现在大多数其他自定义任务(在Python 2.6或更高版本中)更容易使用类装饰器实现,类装饰器可以在class语句结束后立即更改类对象.还有一些情况下这是不可行的,因为如果它们要产生任何影响(例如,设置或改变__slots__),必须尽早进行改变.

在Python 3中,元类获得了一点额外的用处:元类现在可以选择指定在class语句正文执行期间填充的映射对象(默认情况下,它是正常的dict).这允许保留和使用类体中名称绑定的顺序(当正常dict丢失顺序时),当类必须具有特定顺序的"字段"时(例如将1:1映射到C struct,CSV文件或数据库表中的一行等等 - 在Python 2中.*必须冗余地指定(通常使用额外的类属性,这是一个序列,因此保留顺序),并且这个特性Python 3元类允许删除冗余.


Osc*_*Ryz 10

为您的编程增加额外的灵活性:

但根据Python中的Metaclass编程,您可能不需要它们(尚未)

元类比99%的用户应该担心的更深刻.如果你想知道你是否需要它们,你就不会(实际需要它们的人确切地知道他们需要它们,并且不需要解释为什么).

- Python大师Tim Peters

  • 我还是想知道. (19认同)

Mat*_*son 8

我使用一些频率的元类,它们是工具箱中非常强大的工具.有时你的问题解决方案可以更优雅,更少的代码,而不是没有.

我发现自己经常使用元类的事情是在类创建过程中对类属性进行后处理.例如,name在适当的位置设置对象的属性(比如Django ORM可能如何工作):

class AutonamingType(type):
    def __init__(cls, name, bases, attrs):
        for k,v in attrs.iteritems():
            if getattr(v, '__autoname__', False):
                v.name = k

class Autonamer(object):
    __metaclass__ = AutonamingType
Run Code Online (Sandbox Code Playgroud)

如果您将此作为工具,并且您正在使用必须知道它的类,name它可以do_something():

class Foo(object):
    __autoname__ = True
    def __init__(self, name=None):
        self.name = name
    def do_something(self):
        if self.name is None:
            raise ValueError('name is None')
        # now, do something
Run Code Online (Sandbox Code Playgroud)

它可以使你的代码中的其余代码区别开来:

class Bar(object):
    myfoo1 = Foo('myfoo1')
    myfoo2 = Foo('myfoo2')
    myfoo3 = Foo('myfoo3')
Run Code Online (Sandbox Code Playgroud)

还有这个:

class Baaz(Autonamer):
    myfoo1 = Foo()
    myfoo2 = Foo()
    myfoo3 = Foo()
Run Code Online (Sandbox Code Playgroud)

从而减少重复(以及变量名称和分配的名称可能不同步的可能性).

  • 要在没有元类的情况下实现类似的自动命名行为,从 Python 3.6 开始,您可以使用 [__set_name__](https://docs.python.org/3/reference/datamodel.html#object.__set_name__) 方法将 Foo 转换为描述符。 (2认同)

sat*_*oru 5

如果您正在寻找使用元类机制的示例,您可以阅读django.forms的源代码。

表单定义的声明式风格是通过元类实现的。