Python元类有什么用?

33 投票
8 回答
5273 浏览
提问于 2025-04-15 17:39

元类能做哪些其他方法做不到的事情呢?

Alex Martelli提到,有些任务是必须用元类才能完成的,具体可以参考这里 Python元类与类装饰器。我想知道那些任务具体是什么?

8 个回答

9

我经常使用 metaclass( metaclass 是一种特殊的类),它们是一个非常强大的工具,能帮助我们解决问题。有时候,使用它们能让我们的解决方案更优雅,代码更少。

我最常用 metaclass 的地方,是在创建类的时候对类的属性进行后处理。比如说,在合适的地方给对象设置一个 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

如果你有这个工具,并且你正在使用一个在执行 do_something() 之前必须知道自己 name 的类:

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

这可以让你在代码的其他部分之间有很大的不同,比如:

class Bar(object):
    myfoo1 = Foo('myfoo1')
    myfoo2 = Foo('myfoo2')
    myfoo3 = Foo('myfoo3')

和这个:

class Baaz(Autonamer):
    myfoo1 = Foo()
    myfoo2 = Foo()
    myfoo3 = Foo()

这样可以减少重复代码(也降低了变量名和赋值名不同步的可能性)。

13

给你的编程增加一些灵活性:

不过根据这篇Python中的类的编程,你可能暂时不需要它们。

元类是比99%的用户应该担心的事情更复杂的东西。如果你在想自己是否需要它们,那你其实是不需要的(真正需要它们的人会很清楚自己需要,并且不需要解释为什么)。

-- Python大师Tim Peters

20

元类是非常重要的,特别是当你想要创建一些具有“特殊自定义行为”的类对象时。这里的类对象和类的实例是不同的。一个对象的行为是由它的类型上的特殊方法决定的,而类对象的类型恰好就是元类。

举个例子,如果你想要一个类对象 X,当你打印 X 的时候能显示“现在是早上8:46”,这就意味着 type(x)(也就是 X 的元类)需要有一个特别的 __str__ 方法。类似地,如果你想让表达式像 X + Y(X 和 Y 都是类对象)或者 X[23](X 也是类对象)有意义,你也需要相应的特殊方法。

在 Python 2.6 及更高版本中,大多数其他的自定义任务可以通过类装饰器来更简单地实现。类装饰器可以在 class 语句结束后立即修改类对象。不过,有一些情况是不能这样做的,因为这些修改必须在很早的时候就进行,才能生效(比如设置或修改 __slots__)。

在 Python 3 中,元类又多了一点用处:元类现在可以选择指定一个映射对象,在执行 class 语句的主体时填充这个对象(默认是一个普通的 dict)。这使得类主体中名称绑定的顺序得以保留并使用(而普通的 dict 是不保留顺序的)。这在类需要以特定顺序有“字段”时非常有用,比如要和 C 语言的 struct、CSV 文件或数据库表中的一行一一对应。在 Python 2.* 中,这种情况需要额外指定(通常是通过一个额外的类属性来保持顺序),而 Python 3 的元类特性则可以去掉这种冗余。

撰写回答