我们上一篇文章介绍了什么是元类、元类的作用,以及创建类的2种方式,最后是创建如何定义元类,在python
中,有一个特殊的类,称之为type
类,也是元类。我们创建的所有类都基于此。
本篇文章,我们将继续介绍元类的用法。
元类的生命周期
我们之前介绍过,关于类的生命周期,这里先简单回顾下,如果将类实例化对象后,会执行内置方法为:会先执行__new__
内置方法 而后会执行 __init__
内置方法。当我们执行对象的时候,会执行__call__
内置方法。
如果该类不是基于type
来创建的,而是基于我们自己的元类,那么生命周期应该是怎么样的呢?
我们可以和之前探讨类的生命中周期一样,我们写一个案例,使用print
来输出一些信息,来判断如果基于元类而言,那么生命周期是怎么样的。
我们定义代码如下:
上述代码,我们将类ClassName
和其元类mateClass
,我们都重写了__init__
、__call__
、__new__
以及__del__
方法。我们暂时先不管这些方法中的语句含义,我们先执行一次代码,看看执行结果:
哎,你是否感觉好奇,为什么我们还没有开始执行c = ClassName()
就已经执行了mateClass
类中的__new__
方法 和 __init__
方法呢?
这是因为我们在定义ClassName
类的时候指定了其元类mateClass
,所以当我们定义ClassName
的时候,就会去执行该元类的__new__
方法 和 __init__
方法。
随后我们执行了c = ClassName()
,这个是它会执行mateClass
的__call__
方法,我们之前有介绍过,__call__
方法不是要c()
才调用么? 为什么这里调用了呢?
这是因为我们指定元类的时候,代码如下:
class ClassName(metaclass=mateClass):
这里打个比方,上述代码它相当于定义了一个ClassName
,其类型为mateClass
,所以当我们在执行c = ClassName()
就会触发其类的__call__
方法,所以会执行ClassName
的__call__
方法。
随后才执行ClassName
的__new__
方法 和 __init__
方法。而后执行函数,最后销毁的时候,先销毁ClassName
再 销毁mateClass
。
那我们将其整理一下的话,可以图示为:
元类是如何控制类的创建过程的
上面已经演示了元类的生命周期,本篇文章我们将来看下,元类是如何控制类的创建过程的。
在此之前,我们要知道,元类通过什么样的方式来定义的类,可以看到我们上述的代码,在元类中的__new__
方法中,我们返回了如下语句:
class mateClass(type): def __new__(cls, *args, **kwargs): newCls = super().__new__(cls, *args, **kwargs) return newCls
该语句会创建一个新类,随后将该类返回回去。
所谓的控制类的创建过程,我们就可以在该__new__
中判断,传入的参数等信息,比如说,我们想要严格规定创建的类名,不少于6个字符,不多于20个字符,这个如何如何编写呢? 我们可以在元类中的__new__
方法下获取传上来的类名,而后将其对比,若符合规则则返回类,若不符合规则,跑抛错:
class mateClass(type): def __new__(cls, *args, **kwargs): classname = args[0] nameLen = len(classname) if nameLen >= 6 and nameLen <= 20: newCls = super().__new__(cls, *args, **kwargs) return newCls else: msg = "Class name %s does not meet the specifications" % (classname)
上述代码,使我们定义了一个类mateClass
,其继承type
类,在该类中,我们重写了__new__
方法,在该方法中,我们首先获取类名args[0]
将其赋值给classname
,而后进行匹配,若长度大于6且小于20,则创建类,否则就抛错。
上述代码,使我们定义了一个类mateClass
,其继承type
类,在该类中,我们重写了__new__
方法,在该方法中,我们首先获取类名args[0]
将其赋值给classname
,而后进行匹配,若长度大于6且小于20,则创建类,否则就抛错。
介于此,我们可以创建类,将元类指向mateClass
,例如:
class ClassName(metaclass=mateClass): pass
该类名就符合规则,不会报错,若将名称更换为其他不符合规则的名称,则会抛错:
例如:
class d123(metaclass=mateClass): pass
若我们将名称修改为长名称,如:
class d888888888888888abdassd(metaclass=mateClass): pass
执行代码后,也会抛错:
这个案例就是所谓的使用元类来控制类的创建等。非常灵活,也非常强大。
总结
本篇文章,我们先介绍了元类的生命周期,元类的生命周期为,在定义类a
指定其元类时候,元类就会执行__new__
,__init__
方法。在将类a
给实例化的时候,就会执行元类的__call__
方法。后面就和普通的类调用生命周期差不多。后面我们介绍了元类是如何控制类的创建过程的,我们介绍了几个例子来说明该功能。