2.1.6 面向对象:一切皆对象(Python)

本文来自异想之旅公开发布的Python教程,原文地址:https://www.yuque.com/yxzl/python

表象展示

Python 是一门面向对象的程序设计语言,它的设计理念之一便是“一切皆对象”。

一个最简单的字符串就是一个str类的对象:

a = 'abc'
print(type(a))  # <class 'str'>

我们可以对a进行upper()等操作,因为str类实现了这些方法:

a = 'abc'
print(a.upper())  # ABC

事实上,Python 的基础数据类型全部是类:

print(str, int, float, bool, list, dict)
# <class 'str'> <class 'int'> <class 'float'> <class 'bool'> <class 'list'> <class 'dict'>

甚至包括作为关键字的True也是bool类的对象:

print(type(True))  # <class 'bool'>

就连函数也难逃一劫:

def f():
    ...

print(type(f))  # <class 'function'>

看,到处都是class

原理刨析

新手不友好,看不懂请快跑

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

class F:
    ...

class A(F):
    ...

class B(F, object):
    ...

a = A()

print(F.__bases__)  # (<class 'object'>,)
print(A.__bases__)  # (<class '__main__.F'>,)
print(B.__bases__)  # (<class '__main__.F'>, <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……

这里先来一张图简单表示一下这几者的关系,舒缓一下情绪:

在这里插入图片描述

蓝色箭头由实例对象指向实例化它的类,红色箭头由子类指向父类。

值得注意的是,这个图有几个关键的地方:

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

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

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

这部分都是比较好理解的,但关键的问题是——**object**类作为**type**类的父类,怎么会是由**type**类实例化出来的?还有**type**类居然是由**type****自己实例化出来的?**这都是什么操作?

我们可以看看在源码中,type类和object类分别是什么(Python 的底层是 C 的实现,下面的源码如果看不懂的话请别在意,因为不妨碍理解):

在源码中,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的关系了:

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

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

在这里插入图片描述

梅开二度了,那么也还是再提醒一下:蓝色箭头由实例对象指向实例化它的类,红色箭头由子类指向父类。

不理解的可以再看另一个作者的图:实线箭头表示继承关系,由子类指向父类;虚线箭头表示实例化,由实例对象指向实例化它的类。

在这里插入图片描述


后半部分参考和转载自:

猜你喜欢

转载自blog.csdn.net/weixin_44495599/article/details/126184866