洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

时间:2021-12-04 19:12:27

type函数的隐藏属性

相信大家都知道内置函数type是用来查看对象的数据类型的。例:

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

那比如我对int类查看类型呢?

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

有朋友会说,int是内置类啊,用自定义的应该不会这样,我们自定义一个类呢?

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

还是【type】,那如果使用python2,不继承object类呢?

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

哎,果然,不继承object类就没事了,但它是还是一个类对象(classobj)啊,换句话说它还是一个对象啊,那我们用isinstance看看test是不是对象呢?

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

返回True,果然是啊,那再看看基类object呢?

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

还是这个【type】,还是逃不了

那这个【type】又是什么呢?

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

结果是它自身

那么这【type】到底是什么?type类,有吗?不急着说,先说说type另一个功能,这个功能却没多少人知道,在 Stack overflow有一位大神e-satis说,它还能创建类,是不是想说,卧槽,这么吊?确实可以的

先看看type函数到底有哪些用法:

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

其中有个用法:

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

那么这个怎么用呢?

试试看:

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

试试用class关键词定义一样否呢?

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

好像一样的,对吧?不急着下结论,传入属性看看:

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

哎呀,一样的,继承一个类呢?

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

确实一样的。要注意的是,使用type时第二个参数是继承对象,因为参数必须是个元组,当只有一个元素时,得加入逗号才能表示是一个元组(这个在前面元组篇说过的)

那么这是什么原理呢?

首先,我们在之前就掌握的知识点——类也是对象,你可以动态的创建类,可以给类进行重新赋值,复制,添加属性,添加方法等操作,当使用class关键字创建类时,在python内部是怎么操作的?这就是通过元类来实现的。

元类(metaclass)是什么

元类就是用来创建类的“工具”,当创建类目的就是为了创建类的实例对象对吧?需要实例化类对象才能进行我们想要的操作,实现我们希望实现的功能对吧?创建好类后,能够通过类创建出实例化的对象,而类本身也是一个实例对象,不过它是元类的实例对象。而我们已经知道类也是对象。那么,你有没有想过,类这个对象又是被谁创建的呢?我们用class关键词创建时,python是怎么识别并创建类对象的呢?

从表层上说,这是python的解释器自动创建的这个类,从深层上说,这是元类“搞的鬼”,元类就是用来创建这些类(对象)的,元类就是类的类,你可以这样理解

元类和type有什么关系?

在刚才的例子里:

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

type实际上是一个元类metaclass)。type就是Python在背后用来创建所有类的元类。可以类比一下,int是用来创建整数对象的类,list是用来创建列表对象的类,str是用来创建字符串的类等等的,而这些int类,list类,dict类等等全部都是对象,全部都从一个类创建而来——type:

比如博文的最开始a=3这个例子:

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

所以,元类就是创建类这种对象的工具或者东西,type就是Python的内建元类

当然你可以创建自己的元类(如果你想的话)

自定义元类

1.__metaclass__属性

要想创建自己的元类,就得使用__metaclass__属性

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

当使用class Test()创建类时,此时Test还不存在于内存中,当使用了__meaclass__就会用元类来创建类Test,这时python会在类的定义中寻找__metaclass__属性,如果有这个属性,就会创建。如果没有就会用内建的type来创建这个类对象。

当然,如果使用继承也是一样的,比如:

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

使用继承的话,python会判断Test是否有__metaclass__属性,如果有就通过__metaclass__创建,如果没有又从继承的父类Parent类里找有没有__metaclass__,如果有就通过__metaclass__创建,如果还是没有则查找当前主程序模块(__main__,是的,就是 【if __name__ == '__main__'】里的__main__)查找是否有__metaclass__属性,同样的,有就通过其创建,没有就用内置的type创建这个类对象

 这里我个人的理解是:在创建类时,python会判断是否有__metaclass__属性,如果有则按照__metaclass__的特性来创建,如果没有则直接用type来创建一个普通的类,比如一个list,int,str类。

那么我们可以在__metaclass__属性里放置什么呢?可以放置一个type来创建类对象的工具(也可以是type的子类)

洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系

2.元类定义的目的

元类的主要目的就是为了当创建类时能够自动地改变类。通常的用途在于可以在web框架或者API做这样的事情,只要是希望可以创建符合当前上下文的类

自己去体会django里的用法,你会发现,格式是创建的类的格式,但是效果和每行代码的意思完全和常识的类无关了。

元类本身而言,它们其实是很简单的:

  • 拦截类的创建(到底用__metaclass__还是用type来创建)
  • 修改类(__meta__=type……)
  • 返回修改之后的类

3.使用元类的原因

“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。”  —— Python界的领袖 Tim Peters

换句话就是,当我们在想搞清楚什么时候需要用到元类时,那么你就不需要用它了,要用它都是非常清楚它能干什么的。知道这个就行,如果没有接触到深层次的开发,不用管它。并且,元类是很复杂的。对于非常简单的类,没必要通过使用元类来对类做修改