什么是元类

元类是什么

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/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球