在学python?type、object、class这些不了解一下吗?

  • Post author:
  • Post category:python


在Python的学习中我们肯定会听到一句话:

「python中一切皆对象」

如果再接着学习下去的话,我们就会接触到Python中的type, object, class等概念。网上也有不少文章阐述了这三者之间的关系,但是在看了大部分文章之后我还是似懂非懂,感觉就像有什么东西卡在了喉咙一直咽下不去一样。

于是为了能让自己晚上顺利吃上饭,我立马对着搜索引擎就是一顿操作,终于赶在外卖小哥打响我电话之前,咽下了这几个如鲠在喉的概念,舒服!

趁着外卖小哥上楼这会,分享下我学习研究后的理解吧。

python中的对象

python作为面向对象的语言之一,符合一切基于面向对象理念的设计。在面向对象的体系中,对象存在着两种关系。

继承关系

简单来说即子类继承于父类,子类拥有其自身及父类的方法和属性,同名的子类方法和属性将会覆盖父类的方法和属性。

语义化的理解栗子为:

「蛇」类继承自「爬行动物类」,所以「蛇是一种爬行动物」,英文说「snake is a kind of reptile」



在python中的继承关系可以简单表示如下:

class Reptile:
    title = '爬行动物'
    def crawl(self):
        print(self.title)

class Snake(Reptile):
    def crawl_a(self):
        print(self.title)

p = Snake()
p.crawl()  # 爬行动物
p.crawl_a() # 爬行动物
print(p.title) # 爬行动物

上面这个栗子中,子类Snake继承了父类Reptile的title属性和crawl方法,使得类B的实例对象b能调用父类的a属性和get方法。

另外,如果要查看一个类(class)的父类,可以使用

class_name.__bases__

的形式来查看。

Snake.__bases__ # (<class '__main__.Reptile'>,)

实例化关系

如果继承关系好比父与子的关系,实例化关系则是一个从抽象到具体的过程。实例是某个类中具体的个体的表示。

语义化的理解栗子为:

「小p是一条蛇」,「蛇」是一个分类,「小p」则是这个分类中的一个具体的个体。英文说「小p is an instance of snake」

class Snake:
    pass

p = Snake() # p是Snake类的实例对象

如果想要查看一个对象是由哪个类实例化而来,可以使用

type()



object_name.__class__

来查看。表示对象属于什么类型。

type(p) # <class '__main__.Snake'> 表示对象p是由类Snake实例化而来,p的类型是Snake
p.__class__ # <class '__main__.Snake'> 表示对象p是由类Snake实例化而来,p的类型是Snake

探究对象的秘密

有了以上的基础,我们就可以一步一步来探究python中对象潜藏着一些秘密了。嘿嘿嘿~

先看看下面朴而不素的代码:

class A:
    pass

a = A()

print(A.__bases__) # (<class 'object'>,)
print(object.__bases__) # ()
print(type(a)) # <class '__main__.A'>
print(type(A)) # <class 'type'>
print(type(object)) # <class 'type'>
print(type.__bases__) # (<class 'object'>,)

通过上面的很简单的代码,运用

一眼洞穿法

,我们可以根据每个打印语句的结果得到一些简单的观察结论:


  1. 如果定义一个类时没有指定继承哪个类,则默认继承object类


  2. object类的父类为空,说明object类位于继承关系链的顶端,object类是Python中所有类的父类,可以说object是python中的顶端类

  3. 对象a由类

    A

    实例化而来,a的类型为

    A

    ,这个比较容易理解。
  4. 根据3的观察结果,同样的观察手法运用在类A上,观察到类A是由

    type

    这个类实例化而来,类A的类型为

    type

    ,说明

    类A是一个类的同时也是一个对象

    (类A是类type的实例化对象)。这里可能有点晕但是请先接着看下去吧。
  5. 根据3的观察结果,同样的观察手法运用在顶端类object上,观察到

    object

    这个顶端类也是由

    type

    这个类实例化而来,类

    object

    的类型也为

    type

    ,也说明object作为一个类的同时也是一个对象。

  6. 类`type`作为实例化类`A`和类`object`的类,其父类为`object`

看完上面的这些观察结论,相信有一部分童鞋已经两眼发懵了,什么类A是一个类也是一个对象,object类的类型是type,而type类的父类又是object…blablabla

诶,莫方莫方,俗话说无图言*,这里先来一张图简单表示一下这几者的关系,舒缓一下情绪:

python中type,class,object三者关系图
python中type,class,object三者关系图

下面我们就可以开始看图写作文啦~

蓝色箭头由实例对象指向实例化它的类,红色箭头由子类指向父类。值得注意的是,这个图有几个关键的地方:

  • 类(如class A, class object)都是由type这个类实例化而来的,即所有类(class)对象的类型都是type
  • type这个类也是由type自己实例化而来的(图中type处指向自身的部分),即type类的类型也为type
  • type类的父类是object类

有了以上的铺垫,我们可以知道一个最普通的实例对象链是这样子的:


type --实例化--> object --衍生--> class --实例化--> a(具体对象)

这部分都是比较好理解的,但关键的问题是 ————

object类作为type类的父类,怎么会是由type类实例化出来的?还有type类居然是由type自己实例化出来的?

这都是什么操作?

个人认为,这两个问题解决了才能更好地理解type、class、object三者的关系。然而要知道为什么python是这样设计的,最好的做法便是去翻他们的源码啦。不过在翻之前,其实已经有一些大佬对python的源码做了解读,通过搜索引擎认真找寻便可找到想要的答案。python的底层是C的实现,下面的源码如果看不懂的话请别在意,因为不妨碍理解。

(⊙o⊙)

我们可以看看在源码中,

type

类和

object

类分别是什么:


type

类实际上是:

#define PyVarObject_HEAD_INIT(type, size)
    1, type, size,

PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                                     /* tp_name */
    sizeof(PyHeapTypeObject),                   /* tp_basicsize */
    sizeof(PyMemberDef),                        /* tp_itemsize */
    0,                                          /* tp_base */
    ...
}


object

类实际上是:

PyTypeObject PyBaseObject_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "object",                                   /* tp_name */
    sizeof(PyObject),                           /* tp_basicsize */
    0,                                          /* tp_itemsize */
    0,                                          /* tp_base */
    ...
}

这两个类结构体中的各项的具体含义这里不做深究,因为不在本文研究范围内。我们只需要关注这两个结构中的第一行:


PyVarObject_HEAD_INIT(&PyType_Type, 0)

它表示这个类结构的对象类型。能看出来

object

类 和

type

类的对象类型都是

&PyType_Type

,而

PyType_Type

正是底层表示type类的结构体!

这两个结构体就说明了:


object

类将类型(即谁实例化了这个类)设置成了

type

类,

type

类将类型设置成了自己!这其实是python底层实现的一个小小的trick~

然后在

type

类的初始化过程中,执行了如下代码:

type->tp_base = &PyBaseObject_Type;

转换成python为

type.__base__ = (object,) 

表示将object类指定为type类的父类,这不就是第二个问题的答案所在吗?

源码看到这里,前面的两个问题就已经全部解决了,我们可以开始全面总结一下type,class,object的关系了。

总结

type,class,object三者关系:

  • object类是所有类(class)的父类,包括type类,object类的父类为空。
  • type类是所有类的类型,即为所有类(class)都可由type实例化而来,包括type类自己。

    将上面的关系总结成一张图就是:

    pyhton三者关系全
    pyhton三者关系全

后记&引用

写到这里,python中这三者的关系探究就差不多了,只能说技术写作不是一件容易的事情,前后改了不少东西还是不那么让自己满意,但是已经按照自己的意思给表述出来了,希望之后能写得更顺手一些。话说外卖小哥已经在门口等了我5分钟了,写文章死了那么多脑细胞,胃口一定不错吧哈哈。

参考文章:

读后三连⭐️

如果你觉得这篇内容对你有帮助,我想邀请你帮我三个小忙:

  1. 点赞,让更多的人也能看到这篇内容(这对我真的很重要)
  2. 关注公众号「py一下」,不定期分享原创知识,python/后端/业务/数据结构与算法等
  3. 也多看看其他文章



版权声明:本文为qq_29785317原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。