元类是什么
Python程序员经常说一句话:”一切皆对象”,意思是在Python中,你能见到的所有东西,包括int, float, function等等都是对象。但是在日常的开发中,当说到对象的时候,我们可能不会马上就想到类。实际上类也是对象,既然类也是对象,那么就存在一种途径来创建一个类,这就是元类出场的地方,元类就是创建类的类。
元类做了什么
元类会拦截类的创建过程,对类进行修改,然后返回修改后的类。
仅仅看上面这一句话,元类似乎很简单,但是由于元类可以改变一个类的创建过程,可以在其中做一些奇技淫巧的事情,就会让整个事情变得异常晦涩难懂。
type是python中一切类的元类,对一个对象一直调用type(),就会发现最终都会指向type, type比较特殊,type自己是自己的元类。
可以使用type这样创建一个类
其中,type接受的第一个参数是类的名字,第二个参数是一个元组,用来指定需要继承的类,第三个参数是一个字典,在这个字典里面可以把一个类需要的属性、方法用一个字典放进去,这样所有这个元类生成的类都会具有这些属性。
上面的代码等效于下面的代码:
此外,也可以通过type创建自己的元类,然后用这个元类来创建类:
在上面的元类中我们对类的属性进行了检查,如果类的属性不是小写的(不符合PEP8 风格),那么我们强制把类的属性转换成小写。通过这种方式,我们强制子类符合一定的编码风格(子类的属性都必须是小写),这只是元类应用中的hello word,使用元类还可以做更多其它的事情。
我们来实现一个稍微复杂一点的需求。
我们知道Python中的namedtuple可以很方便地用来表述一条数据,假设我们要用元类实现一个namedtuple,为了简单起见,我们只要求这个实现可以接受位置参数,一个可能的实现是这样的:
这样,我们就拥有了一个简单的具名元组,我们可以像使用Python的namedtuple一样进行使用
元类中需要注意的几个方法
元类中,我们通常通过定义__new__或者__init__或者__call__来控制类的创建过程,__new__在类创建之前调用,可以在类创建之前进行一些修改操作,__init__在类被创建之后,对被创建的类进行一些修改,__call__在实例化类的时候调用,通常情况下,我们只需要定义其中一个就足够了,具体使用哪个,可以根据业务场景进行选择。
此外,如果需要接受额外的参数,我们还需要定义__prepare__方法,这个方法会为类准备命名空间,但是通常都不需要定义这个方法,使用默认的就可以了。
比如我们要用元类实现一个单例模式,下面是一个简单的例子:
在上面的例子中,我们在元类中实现了__call__方法,在对类实例化的时候进行检查,如果类已经有实例了,我们就返回已有的实例,保证类只会实例化一次。当然这个元类还有很多缺陷,比如多个类都用这个元类的时候,实际上实例会混淆,这是另一个问题,先不在这里展开。
元类怎么用
答案就是:通常情况下你不需要使用元类
关于元类的使用,Python里面有一个广泛传播的解释,原版如下:
在我们开发工作中,我们实际很少会遇到需要需要动态创建一个类的地方,万一我们遇到了需要动态改变一个类的时候,我们还可以通过类装饰器和猴子补丁实现,这两种方法相比于元类都更加容易理解。
上面的例子只是元类使用场景里面的一些极简示例,主要在于对元类有一个初始的认知,真正用到元类的场景及其实现都会比上面的例子复杂很多,目前,我们只需要知道下面两个点就可以了。
- 类创建实例,元类创建类,元类的实例是类
- 一般情况下,不需要使用元类
Original: https://www.cnblogs.com/buxizhizhoum/p/15545054.html
Author: Go_Forward
Title: 什么是元类
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/685881/
转载文章受原作者版权保护。转载请注明原作者出处!