作者: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)
import traceback
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__)
The reptile class: is a child/kind of <class 'object'> is an instance of <class 'type'> The snake class: is a child/kind of <class '__main__.reptile'> is an instance of <class 'type'> The Squasher class: is an instance of <class '__main__.snake'>
这两种关系使用下面这张图简单示意,继承关系使用实线从子到父连接,类型实例关系使用虚线从实例到类型连接:
我们将使用一块白板来描述一下Python里面对象的关系,白板划分成三列:
先来看看 type
和 object
:
print("object is a instance of %s" % object.__class__)
print("type is a instance of %s" % type.__class__)
object is a instance of <class 'type'> type is a instance of <class 'type'>
它们都是 type
的一个实例,表示它们都是类型对象。
在 Python 的世界中,object
是父子关系的顶端,所有的数据类型的父类都是它;
type
是类型实例关系的顶端,所有对象都是它的实例的。
它们两个的关系可以这样描述:
object
是一个 type
,object
is and instance of type
。即 object
是 type
的一个实例print(object.__class__)
<class 'type'>
print(object.__bases__) # object 无父类,因为它是链条顶端。
()
type
是一种 object
, type
is kind of object
。即 type
是 object
的子类。print(type.__bases__)
(<class 'object'>,)
print(type.__class__) # type的类型是自己
<class 'type'>
此时,白板上对象的关系如下图:(实线为父子关系,虚线为实例类型关系)
我们再引入list, dict, tuple 这些内置数据类型来看看:
print(list.__bases__)
print(list.__class__)
(<class 'object'>,) <class 'type'>
print(dict.__bases__)
print(dict.__class__)
(<class 'object'>,) <class 'type'>
print(tuple.__bases__)
print(tuple.__class__)
(<class 'object'>,) <class 'type'>
它们的父类都是 object
,类型都是 type
。
再实例化一个list
看看:
mylist = [1,2,3]
print(mylist.__class__)
<class 'list'>
try:
print(mylist.__bases__) # 实例化的 list 的类型是 <type 'list'> , 而没有了父类。
except:
print(traceback.format_exc())
Traceback (most recent call last): File "<ipython-input-12-59fac647decb>", line 2, in <module> print(mylist.__bases__) # 实例化的 list 的类型是 <type 'list'> , 而没有了父类。 AttributeError: 'list' object has no attribute '__bases__'
把它们加到白板上去:
白板上的虚线表示源是目标的实例,实线表示源是目标的子类。即,左边的是右边的类型,而上面的是下面的父亲。
虚线是跨列产生关系,而实线只能在一列内产生关系。除了type和object两者外。
当我们自己去定个一个类及实例化它的时候,和上面的对象们又是什么关系呢?试一下:
class C(object):
pass
print(C.__class__)
<class 'type'>
print(C.__bases__)
(<class 'object'>,)
实例化:
c = C()
print(c.__class__)
<class '__main__.C'>
try:
print(c.__base__) # 这个实例化的 C 类对象也是没有父类的属性的。
except:
print(traceback.format_exc())
Traceback (most recent call last): File "<ipython-input-16-f7717e16a19f>", line 2, in <module> print(c.__base__) # 这个实例化的 C 类对象也是没有父类的属性的。 AttributeError: 'C' object has no attribute '__base__'
再更新一下白板:
白板上的第一列,目前只有 type
,我们先把这列的东西叫 Type
。
白板上的第二列,它们既是第三列的类型,又是第一列的实例,我们把这列的对象叫 TypeObject
。
白板上的第三列,它们是第二列类型的实例,而没有父类(__bases__
)的,我们把它们叫 Instance
。
你以为事情就这样完了?
不。。看见 type
孤零零在第一列其实不是那么舒服。。我们给它整几个玩伴看看。
但要怎么整呢?
要属于第一列的,必须是 type
的子类,那么我们只需要继承 type
来定义类就可以了:
class M(type):
pass
print(M.__class__)
<class 'type'>
print(M.__bases__)
(<class 'type'>,)
嗯嗯,M 类的类型和父类都是 type
。
这个时候,我们可以把它归到第一列去。
那么,要怎么样实例化M类型呢?
实例化后它应该出现在那个列?
嗯嗯,好吧,刚才你一不小心创建了一个元类,MetaClass
!即类的类。
如果你要实例化一个元类,那还是得定义一个类:
class TM(object, metaclass=M): # 这样来定义元类(@py3)
# __metaclass__ = M # 这样来指定元类(@py2)
pass
print(TM.__class__) # 这个类不再是 type 类型,而是 M 类型的。
<class '__main__.M'>
print(TM.__bases__)
(<class 'object'>,)
好了,现在 TM 这个类就是出现在第二列的。
再总结一下:
第一列,元类
列,type
是所有元类的父亲。我们可以通过继承 type
来创建元类。
第二列,TypeObject
列,也称 类
列,object
是所有类的父亲。大部份我们直接使用的数据类型都存在这个列的。
第三列,实例
列,实例是对象关系链的末端,不能再被子类化和实例化。到现在为止,Python 类型的秘密已经说穿了,不一小心连元类也暴露了。
哎。慢慢消化吧,信息量很大。如果转述版看不懂,那么去啃一啃原文的吧: Python Types and Objects
=============更新=============
更新更新。。
回答一下题主在问题后面说的为什么要有两个,而不是一个。
如果 type
和 object
只保留一个,那么一定是 object
。
只有 object
时,第一列将不复存在,只剩下二三列,第二列表示类型,第三列表示实例,这个和大部分静态语言的类型架构类似,如 java
。
这样的架构将让 python 失去一种很重要的动态特性 —— 动态创建类型。
本来,类(第二列的同学)在 Python 里面是一个对象( typeobject
),对象是可以在运行时动态修改的,所以我们能在你定义一个类之后去修改他的行为或属性!
拿掉第一列后,第二列变成了纯类型,写成怎样的,运行时行为就怎样。
在这一点上,并不比静态语言有优势。
所以,以上!