#!/usr/bin/env python # coding: utf-8 # ### Python 的 type 和 object 之间是怎么一种关系? # 作者:jeff kit # 链接:https://www.zhihu.com/question/38791962/answer/78172929 # 来源:知乎 # 整理:catcuts # 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 # 给别人讲解过很多次,但写成文字是第一次。试一试吧,自己主要也是看了这篇文章(Python Types and Objects)才懂的。 # `object` 和 `type` 的关系很像鸡和蛋的关系,先有 `object` 还是先有 `type` 没法说,`obejct` 和 `type` 是共生的关系,必须同时出现。 # 在看下去之前,也要请先明白,在 Python 里面,所有的东西都是对象的概念。 # 在面向对象体系里面,存在两种关系: # - 父子关系,即继承关系,表现为子类继承于父类,如『蛇』类继承自『爬行动物』类,我们说『蛇是一种爬行动物』,英文说『snake is a kind of reptile』。 # 在 python 里要查看一个类型的父类,使用它的 `__bases__` 属性可以查看。 # # - 类型实例关系,表现为某个类型的实例化,例如『萌萌是一条蛇』,英文说『萌萌 is an instance of snake』。 # 在 python 里要查看一个实例的类型,使用它的 `__class__` 属性可以查看,或者使用 `type()` 函数查看。 # # (整理注:父子b, 类实c) # In[1]: import traceback # In[2]: class reptile: pass class snake(reptile): pass Squasher = snake() print("The reptile class:") print("\tis a child/kind of %s" % reptile.__bases__) print("\tis an instance of %s" % reptile.__class__) print("The snake class:") print("\tis a child/kind of %s" % snake.__bases__) print("\tis an instance of %s" % snake.__class__) print("The Squasher class:") # print("\tis a child/kind of %s" % Squasher.__bases__) # instance has no parent print("\tis an instance of %s" % Squasher.__class__) # 这两种关系使用下面这张图简单示意,继承关系使用实线从子到父连接,类型实例关系使用虚线从实例到类型连接: # ![](https://pic4.zhimg.com/80/d57e00b9c7a3c1d65573b96ddddf71e8_hd.jpg) # 我们将使用一块白板来描述一下Python里面对象的关系,白板划分成三列: # ![](https://pic3.zhimg.com/80/702d34bae50d2e4f42e0ae4f45e2e996_hd.jpg) # 先来看看 `type` 和 `object` : # In[3]: print("object is a instance of %s" % object.__class__) print("type is a instance of %s" % type.__class__) # 它们都是 `type` 的一个实例,表示它们都是类型对象。 # # 在 Python 的世界中,`object` 是父子关系的顶端,所有的数据类型的父类都是它; # `type` 是类型实例关系的顶端,所有对象都是它的实例的。 # 它们两个的关系可以这样描述: # - `object` 是一个 `type`,`object` is and instance of `type`。即 `object` 是 `type` 的一个实例 # In[4]: print(object.__class__) # In[5]: print(object.__bases__) # object 无父类,因为它是链条顶端。 # - `type` 是一种 `object`, `type` is kind of `object`。即 `type` 是 `object` 的子类。 # In[6]: print(type.__bases__) # In[7]: print(type.__class__) # type的类型是自己 # 此时,白板上对象的关系如下图:(实线为父子关系,虚线为实例类型关系) # ![](https://pic4.zhimg.com/80/d7d23c4f1eded696c72c28cdc3ce9c17_hd.jpg) # 我们再引入list, dict, tuple 这些内置数据类型来看看: # In[8]: print(list.__bases__) print(list.__class__) # In[9]: print(dict.__bases__) print(dict.__class__) # In[10]: print(tuple.__bases__) print(tuple.__class__) # 它们的父类都是 `object`,类型都是 `type` 。 # 再实例化一个`list` 看看: # In[11]: mylist = [1,2,3] print(mylist.__class__) # In[12]: try: print(mylist.__bases__) # 实例化的 list 的类型是 , 而没有了父类。 except: print(traceback.format_exc()) # 把它们加到白板上去: # ![](https://pic3.zhimg.com/80/dcfa446418490a973b8dd47e83c181a8_hd.jpg) # 白板上的虚线表示源是目标的实例,实线表示源是目标的子类。即,左边的是右边的类型,而上面的是下面的父亲。 # 虚线是跨列产生关系,而实线只能在一列内产生关系。除了type和object两者外。 # 当我们自己去定个一个类及实例化它的时候,和上面的对象们又是什么关系呢?试一下: # In[13]: class C(object): pass print(C.__class__) # In[14]: print(C.__bases__) # 实例化: # In[15]: c = C() print(c.__class__) # In[16]: try: print(c.__base__) # 这个实例化的 C 类对象也是没有父类的属性的。 except: print(traceback.format_exc()) # 再更新一下白板: # ![](https://pic1.zhimg.com/80/ca54cfa2cc510d2dcc40e3cc7fb2e051_hd.jpg) # 白板上的第一列,目前只有 `type` ,我们先把这列的东西叫 `Type` 。 # 白板上的第二列,它们既是第三列的类型,又是第一列的实例,我们把这列的对象叫 `TypeObject` 。 # 白板上的第三列,它们是第二列类型的实例,而没有父类(`__bases__`)的,我们把它们叫 `Instance` 。 # 你以为事情就这样完了? # 不。。看见 `type` 孤零零在第一列其实不是那么舒服。。我们给它整几个玩伴看看。 # 但要怎么整呢? # 要属于第一列的,必须是 `type` 的子类,那么我们只需要继承 `type` 来定义类就可以了: # In[17]: class M(type): pass print(M.__class__) # In[18]: print(M.__bases__) # 嗯嗯,M 类的类型和父类都是 `type` 。 # 这个时候,我们可以把它归到第一列去。 # 那么,要怎么样实例化M类型呢? # 实例化后它应该出现在那个列? # 嗯嗯,好吧,刚才你一不小心创建了一个元类,`MetaClass` !即类的类。 # 如果你要实例化一个元类,那还是得定义一个类: # In[19]: class TM(object, metaclass=M): # 这样来定义元类(@py3) # __metaclass__ = M # 这样来指定元类(@py2) pass print(TM.__class__) # 这个类不再是 type 类型,而是 M 类型的。 # In[20]: print(TM.__bases__) # 好了,现在 TM 这个类就是出现在第二列的。 # 再总结一下: # # 第一列,`元类` 列,`type` 是所有元类的父亲。我们可以通过继承 `type` 来创建元类。 # # 第二列,`TypeObject` 列,也称 `类` 列,`object` 是所有类的父亲。大部份我们直接使用的数据类型都存在这个列的。 # # 第三列,`实例` 列,实例是对象关系链的末端,不能再被子类化和实例化。到现在为止,Python 类型的秘密已经说穿了,不一小心连元类也暴露了。 # # 哎。慢慢消化吧,信息量很大。如果转述版看不懂,那么去啃一啃原文的吧: # [Python Types and Objects](http://www.cs.utexas.edu/~cannata/cs345/Class%20Notes/15%20Python%20Types%20and%20Objects.pdf) # =============更新============= # 更新更新。。 # 回答一下题主在问题后面说的为什么要有两个,而不是一个。 # 如果 `type` 和 `object` 只保留一个,那么一定是 `object` 。 # 只有 `object` 时,第一列将不复存在,只剩下二三列,第二列表示类型,第三列表示实例,这个和大部分静态语言的类型架构类似,如 `java` 。 # 这样的架构将让 python 失去一种很重要的动态特性 —— 动态创建类型。 # 本来,类(第二列的同学)在 Python 里面是一个对象( `typeobject` ),对象是可以在运行时动态修改的,所以我们能在你定义一个类之后去修改他的行为或属性! # 拿掉第一列后,第二列变成了纯类型,写成怎样的,运行时行为就怎样。 # 在这一点上,并不比静态语言有优势。 # # 所以,以上! # In[ ]: