Python Types and Objects

0. 背景

本文参考文章知乎回答,同时也安利大家去看看《Python Types and Objects》.

1. 引子

objecttype的关系很像鸡和蛋的关系,先有object还是先有type没法说,obejct和type是共生的关系,必须同时出现的。

在看下去之前,也要请先明白,在Python里面,所有的东西都是对象的概念。

在面向对象体系里面,存在两种关系:
1). 父子关系,即继承关系,表现为子类继承于父类,如『蛇』类继承自『爬行动物』类,我们说『蛇是一种爬行动物』,英文说『snake is a kind of reptile』。在python里要查看一个类型的父类,使用它的__bases__属性可以查看。

2). 类型实例关系,表现为某个类型的实例化,例如『萌萌是一条蛇』,英文说『萌萌 is an instance of snake』。在python里要查看一个实例的类型,使用它的__class__属性可以查看,或者使用type()函数查看。这两种关系使用下面这张图简单示意,继承关系使用实线从子到父连接,类型实例关系使用虚线从实例到类型连接:


这里写图片描述
图1. 蛇的Type和Object的关系图

2. Type and Objects

我们将使用一块白板来描述一下Python里面对象的关系,白板划分成三列:


这里写图片描述
图2. 三白板

先来看看typeobject

>>> object
<type 'object'>
>>> type
<type 'type'>

它们都是type的一个实例,表示它们都是类型对象。

在Python的世界中,object是父子关系的顶端,所有的数据类型的父类都是它;type是类型实例关系的顶端,所有对象都是它的实例的。它们两个的关系可以样描述:

object是一个typeobject is and instance of type。即Objecttype的一个实例。

>>> object.__class__
<type 'type'>
>>> object.__bases__ # object 无父类,因为它是链条顶端。
()

type是一种objecttype is kind of object。即Typeobject的子类。

>>> type.__bases__
(<type 'object'>,)
>>> type.__class__ # type的类型是自己
<type 'type'>

此时,白板上对象的关系如下图:


type and object
图3. Type和Object的三板图

我们再引入list, dict, tuple 这些内置数据类型来看看:

>>> list.__bases__
(<type 'object'>,)
>>> list.__class__
<type 'type'>
>>> dict.__bases__
(<type 'object'>`)
>>> dict.__class__
<type 'type'>
>>> tuple.__class__
<type 'type'>
>>> tuple.__bases__
(<type 'object'>,)

它们的父类都是object,类型都是type

再实例化一个list看看:

>>> mylist = [1,2,3]
>>> mylist.__class__
<type 'list'>
>>> mylist.__bases__
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    AttributeError: 'list' object has no attribute '__bases__'

实例化的list的类型是<type 'list'>, 而没有了父类。

把它们加到白板上去:


这里写图片描述
图4. 加入list, tuple, dict的三板图

白板上的虚线表示源是目标的实例,实线表示源是目标的子类。即,左边的是右边的类型,而上面的是下面的父亲。

虚线是跨列产生关系,而实线只能在一列内产生关系。除了typeobject两者外。

当我们自己去定个一个类及实例化它的时候,和上面的对象们又是什么关系呢?试一下:

>>> class C(object):
... pass
... 
>>> C.__class__
<type 'type'>
>>> C.__bases__
(<type 'object'>,)

实例化后:

>>> c = C()
>>> c.__class__
<class '__main__.C'>
>>> c.__bases__
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 AttributeError: 'C' object has no attribute '__bases__'

再更新一下白板:


这里写图片描述
图5. 加入C类后的三板图

1). 白板上的第一列,目前只有type,我们先把这列的东西叫Type。
2). 白板上的第二列,它们既是第三列的类型,又是第一列的实例,我们把这列的对象叫TypeObject
3). 白板上的第三列,它们是第二列类型的实例,而没有父类(__bases__)的,我们把它们叫Instance。

你以为事情就这样完了?不。。看见type孤零零在第一列其实不是那么舒服。。我们给它整几个玩伴看看。但要怎么整呢?要属于第一列的,必须是type的子类,那么我们只需要继承type来定义类就可以了:

>>> class M(type):
... pass
... 
>>> M.__class__
<type 'type'>
>>> M.__bases__
(<type 'type'>,)
>>> 

嗯嗯,M类的类型和父类都是type。这个时候,我们可以把它归到第一列去。那么,要怎么样实例化M类型呢?实例化后它应该出现在那个列?
嗯嗯,好吧,刚才你一不小心创建了一个元类,MetaClass, 即类的类。如果你要实例化一个元类,那还是得定义一个类:

>>> class TM(object):
... __metaclass__ = M # 这样来指定元类。
... 
... 
>>> TM.__class__
<class '__main__.M'> # 这个类不再是type类型,而是M类型的。
>>> TM.__bases__
(<type 'object'>,)

好了,现在TM这个类就是出现在第二列的。

3. 总结

1). 第一列,元类列,type是所有元类的父亲。我们可以通过继承type来创建元类。
2). 第二列,TypeObject列,也称类列,object是所有类的父亲,大部份我们直接使用的数据类型都存在这个列的。
3). 第三列,实例列,实例是对象关系链的末端,不能再被子类化和实例化。到现在为止,Python类型的秘密已经说穿了,不一小心连元类也暴露了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值