最近了解了一下python的metaclass,在学习的过程中,把自己对metaclass的理解写出来和大家分享。
首先, metaclass 中文叫元类,这个元类怎么来理解呢。我们知道,在Python中,一切都是对象。我们定义一个类,然后实例化,得到了一个类的实例对象。我们可以把类理解成创建实例对象的模板。其实,这个模板,也就是类本身,也是一个对象。既然类也是对象,那么我们就可以对他进行很多操作。比如,把类作为函数的参数,创建类的引用等等。那么创建类的模板,就是元类。
在Python中,我们很早就接触了一个函数 type,用来返回对象的类型。比如
In [1]: print(type(1)) <type 'int'> In [2]: print(type("1")) <type 'str'> In [3]: def foo():pass In [4]: print (type(foo)) <type 'function'> In [5]: class Foo():pass In [6]: print(type(Foo())) <type 'instance'> In [7]: print(type(Foo)) <type 'classobj'>
其实 type函数还有另外一个用处,那就是用来创建类,用法就是
type(classname,(superclassname,),{attrs}),我们来看一下:
MyClass = type("MyClass",(),{})
其实等效于
class MyClass(): pass
我们说过,metaclass是创建类的类,所以,type就是一个metaclass。我们来验证一下
In [23]: age.__class__ Out[23]: int In [24]: name.__class__ Out[24]: str In [25]: MyClass().__class__ Out[25]: __main__.MyClass In [26]: MyClass().__class__.__class__ Out[26]: type In [29]: age.__class__.__class__ Out[29]: type In [30]: name.__class__.__class__ Out[30]: type
type是内置的metaclass,我们也可以自己定义自己的元类。在定义类的时候,定义 __metaclass__属性,这种情况下,Python就会使用metaclass 来创建类。具体模式如下:
在创建类时,Python会寻找有没有定义__metaclass__,如果有,就用定义好的metaclass来创建类。
如果在当前类找不到 __metaclass__,Python会在当前模块下寻找__metaclass__
如果还是找不到,Python会寻找当前类第一个父类的__metaclass__,直到最后的内建函数type()
那么__metaclass__定义到底是什么呢?
是任何能够创建类的,比如type或者type的子类
所以metaclass的目的在类创建的时候自动的修改类,举个例子,我们想把一个类里所有的属性前面都加一个my_前缀,使用metaclass的方式就比较简单
class MyAttrMetaclass(type): def __new__(cls, clsname, bases,dct): my_attr = {} for name, val in dct.items(): if not name.startswith('__'): my_attr["my_"+name] = val else: my_attr[name] = val return type.__new__(cls, clsname, bases, my_attr) class Foo(): __metaclass__= MyAttrMetaclass test_age = 1 test_name = "test" print(hasattr(Foo,"test_age")) False print(hasattr(Foo,"my_test_age")) True
可以看到通过元类的方式,我们的类Foo的属性被修改了。
最后一个问题就是我们在什么情况下会用到metaclass呢?
常见的例子有Django ORM 的Model类,
我们定义一个Person类集成Model
class Person(Model): name = models.CharField(max_length=30) age = models.IntegerField() p = person(name="haha",age="31")
p.age 返回的是int 而不是IntegerField(),这就是因为在Model中使用的metaclass动态修改类
本文总结了黑魔法metaclass的定义,用法,主要参考了http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python