一个现实世界的元类例子
在 django.models 或者 peewee 等 ORM 中,我们一般使用类的成员变量来定义字段,这里就用到了元类。
class Field: pass class IntegerField(Field): pass class CharField(Field): pass class MetaModel(type): def __new__(meta, name, bases, attrs): # 这里最神奇的是:用户定义的类中的 bases 和 attrs 都会作为参数传递进来 fields = {} for key, value in attrs.items(): if isinstance(value, Field): value.name = '%s.%s' % (name, key) fields[key] = value for base in bases: if hasattr(base, '_fields'): fields.update(base._fields) attrs['_fields'] = fields return type.__new__(meta, name, bases, attrs) class Model(metaclass=MetaModel): pass
这样用户使用的时候就可以这样定义:
>>> class A(Model): ... foo = IntegerField() ... >>> class B(A): ... bar = CharField() ... >>> B._fields {'foo': Integer('A.foo'), 'bar': String('B.bar')}
程序在执行的时候就可以直接访问 X._fields
,而不用每次都通过反射遍历一次,从而提高效率以及做一些验证。
不过,其实这个完全可以通过装饰器来实现:
def model(cls): fields = {} for key, value in vars(cls).items(): if isinstance(value, Field): value.name = '%s.%s' % (cls.__name__, key) fields[key] = value for base in cls.__bases__: if hasattr(base, '_fields'): fields.update(base._fields) cls._fields = fields return cls @model class A(): foo = IntegerField() class B(A): bar = CharField()
但是用装饰器的话,就失去了一些类型继承的语义信息。
总结与思考
Python 中的元编程还是一种很强大的特性,但是也比较复杂,有时候很难以理解。实际上,过分的动态特性也导致了 Python 的解释器和静态分析、自动补全等很难优化,因为有好多信息必须到运行时才能知道。
实际上近些年新开发的语言越来越多地加入了静态类型的特性,比如 swift, rust, go 等。就连 Python 本身也增加了 type hinting 的功能,很遗憾的是,这个功能不是强制性的,所以也很难用来提升性能。
元类这块应该是我在 Python 语言方面了解的最后一大块知识了。接下来除了写业务代码不会再深究 Python 了,研究 Golang 去了~
Au revoir, Python!