2.5.2.1Python-黑魔法:元类

总目录:https://www.jianshu.com/p/e406a9bc93a9

Python - 子目录:https://www.jianshu.com/p/50b432cb9460

引子

class Foo:

    pass


f=Foo()#f是Foo类实例化的对象


print(type(f))

print(type(Foo))


 

Python的世界里有一个铁律,一切皆为对象,f是一个对象,Foo也是一个对象。而f是Foo这个类产生的对象,那么Foo是谁产生的呢?

我们从输出结果来看,Foo是type类型,那么type就是Foo的类,是用来创造类的类,这种类就是元类。


什么是元类

我们总结一下刚才的结论:

元类就是类的模板,是类的类。

元类的主要目的是为了控制类的创建行为。

type是Python的一个内建元类,用来直接控制生成类,在python当中任何class定义的类其实都是type类实例化的结果。

只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类,自定义元类可以控制类的产生过程,类的产生过程其实就是元类的调用过程。


使用元类

我们来看一下type的源码,能看到需要传三个参数,分别是类名,父类,属性

我们既然说type是元类,那么我们就可以通过type不适用class关键字创建类:

class Foo1:

    x=1

print(Foo1)

print(type('Foo2',(object,),{'x':1}))


我们来看一看调用

class Foo1:

    x=1

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


print(Foo1.x)

1

print(Foo2.x)

1

上面这个例子我们只是添加了一个属性,接下来我们演示一下加入一个方法:

def test(self,name):

    self.name = name


Foo2=type('Foo2',(object,),{'x':1,'test':test})

print(Foo2.__dict__)

{'x': 1, 'test': ,。。。。


自定义元类

我们知道类有继承的属性,那么我们自定义一个类继承元类,是不是就可以根据我们的需要来自定义元类呢。


class Mytype(type):

    def __init__(self,a,b,c):

        print(a)

        print(b)

        print(c)


class Foo(metaclass=Mytype):

def __init__(self,name):

    self.name =name

Foo 

()

 {'__module__': '__main__', '__qualname__': 'Foo', '__init__': }

首先我们知道在type源码中,__init__方法有四个参数,抛去cls,还有传入三个参数,所以我们自定义元类中必须有四个参数

如果没有的话,会报错:

TypeError: __init__() takes 1 positional argument but 4 were given

而我们打印a,b,c三个参数接受的信息时,可以发现他们分别接受了类标识符,父类,属性。

接下来我们开始将类实例化:

class Mytype(type):

    def __init__(self,a,b,c):

        pass


class Foo(metaclass=Mytype):

    def __init__(self,name):

        self.name =name


f1=Foo('hanxuan')

print(f1)

<__main__.Foo object at 0x0000022F4506C320>

这里我们有一个疑问,类在实例化时,元类会干些什么呢?我们这里就需要一个魔法函数--__call__,具体用法看上一节。

同时我们要介绍两个关键的魔法函数:__new__和__init__。

__init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值。

__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例,是个静态方法。

类在进行实例化时,会先指向__new__完成实例化,之后执行__init__完成初始传参。

__new__
Foo

从这两个图就能清楚的分清楚,在执行f1=Foo('hanxuan')时,会指向obj=object.__new__(self),之后将实例化的信息传给f1。

实例

class Mytype(type):

    def __init__(self,a,b,c):

        pass

    def __call__(self, *args, **kwargs):

        obj=object.__new__(self)

        self.__init__(obj,*args,**kwargs)

        return obj


class Foo(metaclass=Mytype):

    def __init__(self,name):

        self.name =name


f1=Foo('hanxuan')

print(f1)

<__main__.Foo object at 0x00000186FCDEC320>

你可能感兴趣的:(2.5.2.1Python-黑魔法:元类)