Python元类有什么用?
元类能做哪些其他方法做不到的事情呢?
Alex Martelli提到,有些任务是必须用元类才能完成的,具体可以参考这里 Python元类与类装饰器。我想知道那些任务具体是什么?
8 个回答
我经常使用 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()
这样可以减少重复代码(也降低了变量名和赋值名不同步的可能性)。
给你的编程增加一些灵活性:
不过根据这篇Python中的类的编程,你可能暂时不需要它们。
元类是比99%的用户应该担心的事情更复杂的东西。如果你在想自己是否需要它们,那你其实是不需要的(真正需要它们的人会很清楚自己需要,并且不需要解释为什么)。
-- Python大师Tim Peters
元类是非常重要的,特别是当你想要创建一些具有“特殊自定义行为”的类对象时。这里的类对象和类的实例是不同的。一个对象的行为是由它的类型上的特殊方法决定的,而类对象的类型恰好就是元类。
举个例子,如果你想要一个类对象 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 的元类特性则可以去掉这种冗余。