python黑魔法之metaclass

最近了解了一下python的metaclass,在学习的过程当中,把本身对metaclass的理解写出来和你们分享。python

 

首先, 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函数还有另一个用处,那就是用来建立类,用法就是spa

type(classname,(superclassname,),{attrs}),咱们来看一下:code

MyClass = type("MyClass",(),{})

其实等效于对象

class MyClass():
    pass

咱们说过,metaclass是建立类的类,因此,type就是一个metaclass。咱们来验证一下blog

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 来建立类。具体模式以下:it

在建立类时,Python会寻找有没有定义__metaclass__,若是有,就用定义好的metaclass来建立类。io

若是在当前类找不到 __metaclass__,Python会在当前模块下寻找__metaclass__function

若是仍是找不到,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 

相关文章
相关标签/搜索