初步认识元类

#本篇文章介绍的元类,以及type以python3以上版本为准。

一.关于元类的前言。

在python中,一切皆对象,当然,类也是一个对象。

class c1:

    pass

obj1 = c1()

从上面这段例子可以看到,obj1是c1这个类创建出来的一个对象,obj1是由c1去产生的,如果按照前面的理论来理解,类也是一个对象,那么c1是由谁创建出来的呢?

#type函数可以查看类型,也可以用来查看对象的类,二者是一样的

print(type(obj1)) # 输出:<class '__main__.c1'>     表示,obj1 对象由c1类创建

 print(type(c1)) # 输出:<type 'type'>  

也就是说我们定义的类,全部都是由type产生的。


通过这个知识点,可以引出两种创建类的方式。

方式一:使用class关键字定义一个类。

class Foo:

     def func(self):

         print('from func')


方式二:通过type定义一个类。

def func(self):

         print('from func')

x=1

Foo=type('Foo',(object,),{'func':func,'x':1})


二.什么是元类?

所谓的元类,可以理解为它是类的类,元类是去控制如何创建一个类的,就像类是对象的模版一样,元类则是类的模版。

type和元类由什么关系呢?

当一个类没有声明自己的元类时,这个类默认的元类就是type。

不止如此,用户还可以通过type来定义一个元类。

注意!当自定义元类的时候,自己定义的元类一定要继承type!


关于元类参数的剖析:


python2.7ver:

class mytype(type):

    def __init__(self,class_name,bases,dict):

        print "mytype __init__ runing!!"

        print class_name    #类的名字

        print bases    #继承的父类

        print dict  #类的名称空间字典(也就是类的__dict__)

        print self   #定义的类的本体(也就是类的内存地址)

class test_class(object):  #将mytype作为元类,创建一个类,名为test_class

    __metaclass__ = mytype   #python2.7中指定元类的方法。

    def running(self):

        print "runing....."

接下来执行以下代码。

输出:

mytype __init__ runing!!

test_class

(<type 'object'>,)

{'__module__': 'test1', '__metaclass__': <class 'test1.mytype'>, 'running': <function running at 0x10e149c08>}

<class 'test1.test_class'>


python3.5ver:

class mytype(type):

    def __init__(self,class_name,bases,dict):

        print("mytype __init__ runing!!")

        print(class_name)    #类的名字

        print(bases)    #继承的父类

        print(dict)  #类的名称空间字典(也就是类的__dict__)

        print(self)   #定义的类的本体(也就是类的内存地址)

class test_class(metaclass = "mytype"):  #将mytype作为元类,创建一个类,名为test_class

    def running(self):

        print("runing.....")

#从输出的结果可以看出,当我们在创建一个类的时候,就会触发元类的__init__构造方法,就好像是用类创建对象的过程一样。


类是如何实例化出属性的呢?下面就通过元类手动来实现这个功能。


python2.7ver:

class mytype(type):

    def __init__(self,class_name,bases,dict):

        print "mytype __init__ runing!!"

        print class_name

        print bases

        print dict

        print self

    def __call__(self, *args, **kwargs):  # 当使用类去实例化一个对象的时候,类后面需要加()这就会触发元类中定义的__call__方法。

        print "mytype call runing -----> %s,%s,%s" %(self,args,kwargs)

        obje  = self.__new__(self) #生成一个空的对象

        self.__init__(obje,*args,**kwargs) #调用元类所创建类的构造方法。

        return obje #将空对象返回

class test_class(object):

    __metaclass__ = mytype

    a = 1

    def running(self):

        print "runing....."

obj1 = test_class()

print obj1.a