Python番外篇:标准类型层次结构

引言

前面的文章中,我们提到了在Python中一切皆对象,理所当然的,函数和类也是对象,所以,函数和类在Python中也是一等公民。
既然,一切皆对象,对象与类的关系是实例化与抽象的关系。
那么,这些对象,是什么类型的呢,也就是说,是由什么类实例化出来的呢?
这些对象所属的类之间的继承关系又是怎样的?
今天这篇文章中,我们来重点探究一下,Python中的标准类型层次结构,从而回答上面的两个问题。
在开始之前,需要再次明确区分一下“继承”与“实例化”这两种关系的区别,不然可能会不小心被绕进去,毕竟类也是对象,可以称之为类对象。

  • 继承:是类与类之间的关系,子类继承父类,这时候,我们只关注类的概念,暂时不考虑类对象的概念。
  • 实例化:是类与对象之间的关系,类可以理解为一个模板,是一个抽象化的实体,对象是基于类这个模板实例化出来的具体的对象。由于类也是对象,所以,谈到实例化时,我们也会探究类对象是有什么类实例化来的。

基础知识

为了更好的能看到对象与类、类与类之间的关系,我们需要一些前置知识。对这些知识,只需要知道、会用即可,这里不需要深究,后面多用,会有更多地体会。

type

前面的文章中,我们经常提到使用type()函数,可以查看一个对象的类型,这个说法其实是不对的。在今天这篇文章中,我们要转变一下观念了,type不是函数,而是一个类!
首先看下builtins中的type定义:

如果没有看过定义,估计有不少初学者或者新手把type当做一个内置的函数。
看定义中的说明文档,我们发现type这个类的初始化函数,可以获取类对象,初始化函数接收的参数,可以是一个对象,也可以是更多的参数。接下来,简单演示一下type类的用法:

# 获取类对象
print(type(5))
# 如果type(5)获取了类对象,那我们是否可以直接用这个类对象继续实例化对象呢
# 等价于 a = int(100)
a = type(5)(100)
print(a)
print(type(a))

执行结果:

此外,从文档看出,我们还可以通过type自定义类对象:

# 自定义MyInt类对象,等价于如下定义:
# class MyInt(int):
#     pass
my_int = type('MyInt', (int,), {})
a = my_int(10)
print(type(a))
b = my_int(20)
print(type(b))
print(a + b)
# 调用父类int的方法
print(type(a + b))

属性__class__

我们知道对象是由类实例化的,前面,我们通过type这个类找到了实例化某个对象的类。如果,不借助type,我们能否通过一个对象本身找到实例化它的类呢?答案是肯定的。
在Python中,对象都有一个特殊的属性:class,通过这个属性,我们也可以获得实例化该对象的类对象:

a = 5
print(a.__class__)
b = a.__class__(10)
print(b)
print(b.__class__)

执行结果:


既然__class__属性指向了一个类对象,我们自然可以通过__class__属性进行实例化对象的操作。

属性__bases__

不管是type类,还是__class__属性,我们要找的都是对象与类之间的关系,也就是实例化关系。
接下来,我们来看一下类与类之间的继承关系。
由于,类也是对象,也就是类对象,类对象也是有自己的属性的,其中__bases__就是指向这个类对象的父类对象的属性。
由于Python中的面向对象是支持多继承的,一个子类可以有多个父类,所以__bases__属性,属性名是一个复数的形式,该属性是一个元组:

a = 5
print(a.__class__.__bases__)
print(int.__bases__)

执行结果:

需要注意的是,只有类对象才有__bases__属性,普通对象必须先找到自身的类对象,才能进一步找到父类。

可以结合前面通过type类自定义类,来进一步看这个类对象的继承关系:

my_int = type('MyInt', (int,), {})
a = my_int(10)
print(type(a))
# a是普通对象
print(a.__class__.__bases__)
# my_int是类对象
print(my_int.__bases__)

执行结果:

Python标准类型层次结构

先说几个关键的结论:
1、Python中所有的类对象,都是通过type类实例化的;
2、Python中所有的类对象的最顶层的父类都是object;
3、object这个类对象是由type类实例化的;
4、type这个类对象是由type类自己实例化的。

有点绕,暂时有个概念,以实践慢慢消化理解吧。

关于Python标准类型的层次结构图,附在本文的结尾。

接下来,通过代码演示常见标准类型的层次结构:

from rich.console import Console

console = Console()

# 查看对象的类型、类对象的类型、类型的父类
def show_class(obj):
    console.rule(str(obj))
    print(obj.__class__)
    print(obj.__class__.__class__)
    print(obj.__class__.__bases__)

show_class(None)
show_class(NotImplemented)
show_class(5)
show_class(True)
show_class(3.14)
show_class('hello python')
show_class(b'hello python')
show_class((1, 2, 3))
show_class([1, 2, 3])
show_class(bytearray([1, 2, 3]))
show_class(set([1, 1, 2, 3]))
show_class(frozenset([1, 1, 2, 3]))
show_class({'a': 1, 'b': 2})
show_class(lambda a, b: a + b)
show_class(sum)

# sys.stdin的类继承层次
console.rule('sys.stdin')
fp = sys.stdin
print(fp.__class__)
print(fp.__class__.__class__)
print(fp.__class__.__bases__)
print(fp.__class__.__bases__[0].__bases__)
print(fp.__class__.__bases__[0].__bases__[0].__bases__)

# code对象
def my_sum(a, b):
    return a + b

show_class(my_sum.__code__)

执行结果:

Python中的标准类型层次结构示意图:
由于篇幅有限,并没有涵盖Python中的完整的类型层次结构。

  • 28
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南宫理的日知录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值