Python metaclass/type 原理详解

2020-04-05  本文已影响0人  虐心笔记

在学习 metaclass 之前先了解一下 type() 和 isinstance() 函数的用法。

内置函数 type()、isinstance()

type()

    主要有两个功能:1.查看变量(对象)的类型。2.动态创建一个类 class,对你没有看错。

示例1: 当传入一个参数或者对象时,返回这个对象的类型

    一般type() 函数都是用来检查对象类型的,从示例可以看出跟 object.__class__ 的功能是一致的,都是返回对象的类型

示例2: 动态创建一个类

class type(name, bases, dict)

name: 要创建的类型
bases: 要创建的类的基类, Python由于允许多继承,这里是一个元组类型
dict: 要创建类的属性,dictionary类型

    上面的类是通过 Person =type('Person', (object,), dict(name='angst')) 创建了一个类 classVariable, 再通过classVariable() 创建了一个实例a。从上面的示例可以看出,两种创建的类是一致的,可以看输出结果类型都是一致的。在一般正常情况下都是通过 class XXX 来定义一个类。但是,type()也是允许动态创建类的,Python是一种解释性的动态语言

isinstance()

isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()

isinstance(object, classInfo)

    object: 要判断的实例对象
    classInfo: 期望的类型,可以是直接或间接类名、基本类型或者由它们组成的元组

isinstance() 与 type() 区别:

    type() 不会认为子类是一种父类类型,不考虑继承关系。
    isinstance() 会认为子类是一种父类类型,考虑继承关系。

注意:如果要判断两个类型是否相同推荐使用 isinstance()

从示例简单可以看出isinstance()与type() 的一些区别,如果想知道子类与父类之间的继承关系还可以用issubclass() 或 object.__bases__


metaclass

    metaclass 元类,可以控制类的属性和类实例的创建过程。如果希望创建某一批类全部具有某种特征,则可通过 metaclass 来实现。使用 metaclass 可以在创建类时动态修改类定义。

对象、类、元类 关系图

在Python 中,一切都可以是对象,整数、字符串、类实例、类本身也是对象,和其他对象一样,它是metaclass 的一个实例。

    从示例的结果可以看出,默认的metaclass 是type类型的,所以我们看到Person 的类型是type,type类型?从这里可以看出有点奇怪,从开始type函数的时候,有说明过type()是可以当做函数来使用的,返回的是一个对象的类型。目前看来就有点困惑了,其实在Python中type是一个极为特殊的类型,为了彻底理解metaclass,需要先理清楚type和object的关系。

type与object 的关系

    在Python3中,object 是所有类的基类,内置的类、自定义的类都是直接或者间接的继承object类,去看源码,会发现type类也是继承object类,那么问题来了?

1.首先 type 是一个metaclass ,而且是一个默认的metaclass,可以理解为type是object的类型,object又是type的一个实例。
2.type 是object 的一个子类,继承object的所有属性和行为
3.type还是一个callable对象,即实现了__call__方法,可以使用type()返回对象的类型

    type 和object的关系是不可分离的,type是object的子类,同时 object又是type的一个实例(type是object的类型),type的类型也是type,看到这里我也有点费劲。但是不管它,知道是怎么回事就行了。难受

自我总结了一下:metaclass 是创建类的那个类。在python3中,我们自己定义的类,比如说Person,Animal类,它们默认的元类就是type。换句话说,Person类,Animal类也是对象,它们是type类的实例对象。因为:一切皆是对象。那么反过来可以说元类的实例就是类。

1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)

2.对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 __call__ 方法

这么讲是不是就好理解多了?

下面我们来自定义一个 metaclass,自定义的metaclass 必须继承 type,自定义的metaclass 通常以Metaclass或Meta作为后缀取名来区分。

所有的累都继承自object,包括内置的类和用户自定义的类都是。一般来说,类class的类型为type(即一般的类的metaclass都是默认type,也就是type的一个实例),如果想改变类的metaclass,那么在定义类的时候,显式的指定它的metaclass即可。

    在自定义metaclass的注意点:

    1. object的__init__方法只有一个参数,单自定义metaclass的__init__有4个。
        def __init__(self): object 只有self参数
        def __init__(cls, what, bases=None, dict=None): 因为自定义的metaclass是继承type,所有必须要有4个参数。继承的super()
     2.对于普通的类,重写__call__ 方法说明这个对象是callable,但在metaclass中__call__ 还负责对象的创建

    下面结果代码示例看一下对象的创建过程

示例代码 测试代码

结合示例来分析一个实例对象的完整创建的过程:

1.metaclass.__init: 首先进行初始化操作
2.metaclass.__call__: 创建实例,在穿件的过程中会调用class 的 __new__/__init__方法
3.class.__new__: 进行具体的实例化操作,并返回一个实例对象 at 0x000001851AC65808>
4.class.__init__: 返回一个实例对象 at 0x000001851AC65808 进行初始化
5. 返回一个用户真正需要的对象 object at 0x000001851AC65808>

 从以上示例结果和对结果的分析,可以看出metaclass是如何定义一个实例对象的,以及对象在生命周期完整创建过程。

本篇学习笔记涉及的技术概念均来自《人人都懂设计模式》,有兴趣的同学可以去看看......

上一篇下一篇

猜你喜欢

热点阅读