洗礼灵魂,修炼python(42)--巩固篇—type内置函数与类的千丝万缕关系
type函数的隐藏属性
相信大家都知道内置函数type是用来查看对象的数据类型的。例:
那比如我对int类查看类型呢?
有朋友会说,int是内置类啊,用自定义的应该不会这样,我们自定义一个类呢?
还是【type】,那如果使用python2,不继承object类呢?
哎,果然,不继承object类就没事了,但它是还是一个类对象(classobj)啊,换句话说它还是一个对象啊,那我们用isinstance看看test是不是对象呢?
返回True,果然是啊,那再看看基类object呢?
还是这个【type】,还是逃不了
那这个【type】又是什么呢?
结果是它自身
那么这【type】到底是什么?type类,有吗?不急着说,先说说type另一个功能,这个功能却没多少人知道,在 Stack overflow有一位大神e-satis说,它还能创建类,是不是想说,卧槽,这么吊?确实可以的
先看看type函数到底有哪些用法:
其中有个用法:
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
那么这个怎么用呢?
试试看:
试试用class关键词定义一样否呢?
好像一样的,对吧?不急着下结论,传入属性看看:
哎呀,一样的,继承一个类呢?
确实一样的。要注意的是,使用type时第二个参数是继承对象,因为参数必须是个元组,当只有一个元素时,得加入逗号才能表示是一个元组(这个在前面元组篇说过的)
那么这是什么原理呢?
首先,我们在之前就掌握的知识点——类也是对象,你可以动态的创建类,可以给类进行重新赋值,复制,添加属性,添加方法等操作,当使用class关键字创建类时,在python内部是怎么操作的?这就是通过元类来实现的。
元类(metaclass)是什么
元类就是用来创建类的“工具”,当创建类目的就是为了创建类的实例对象对吧?需要实例化类对象才能进行我们想要的操作,实现我们希望实现的功能对吧?创建好类后,能够通过类创建出实例化的对象,而类本身也是一个实例对象,不过它是元类的实例对象。而我们已经知道类也是对象。那么,你有没有想过,类这个对象又是被谁创建的呢?我们用class关键词创建时,python是怎么识别并创建类对象的呢?
从表层上说,这是python的解释器自动创建的这个类,从深层上说,这是元类“搞的鬼”,元类就是用来创建这些类(对象)的,元类就是类的类,你可以这样理解
元类和type有什么关系?
在刚才的例子里:
type实际上是一个元类(metaclass)。type就是Python在背后用来创建所有类的元类。可以类比一下,int是用来创建整数对象的类,list是用来创建列表对象的类,str是用来创建字符串的类等等的,而这些int类,list类,dict类等等全部都是对象,全部都从一个类创建而来——type:
比如博文的最开始a=3这个例子:
所以,元类就是创建类这种对象的工具或者东西,type就是Python的内建元类
当然你可以创建自己的元类(如果你想的话)
自定义元类
1.__metaclass__属性
要想创建自己的元类,就得使用__metaclass__属性
当使用class Test()创建类时,此时Test还不存在于内存中,当使用了__meaclass__就会用元类来创建类Test,这时python会在类的定义中寻找__metaclass__属性,如果有这个属性,就会创建。如果没有就会用内建的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的子类)
2.元类定义的目的
元类的主要目的就是为了当创建类时能够自动地改变类。通常的用途在于可以在web框架或者API做这样的事情,只要是希望可以创建符合当前上下文的类
自己去体会django里的用法,你会发现,格式是创建的类的格式,但是效果和每行代码的意思完全和常识的类无关了。
元类本身而言,它们其实是很简单的:
- 拦截类的创建(到底用__metaclass__还是用type来创建)
- 修改类(__meta__=type……)
- 返回修改之后的类
3.使用元类的原因
“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters
换句话就是,当我们在想搞清楚什么时候需要用到元类时,那么你就不需要用它了,要用它都是非常清楚它能干什么的。知道这个就行,如果没有接触到深层次的开发,不用管它。并且,元类是很复杂的。对于非常简单的类,没必要通过使用元类来对类做修改