Python万物皆对象理解及源码学习

目录
  • 万物皆对象
  • 1 类型对象和实例对象
  • 2 类型、对象体系
    • 2.1 元类型type
    • 2.2 自定义类型
    • 2.3 自定义类型子类
    • 2.4 type和object的关系
  • 3 可变对象与不可变对象
  • 4 变长对象和定长对象
  • 5 补充

万物皆对象

这篇博客的内容主要是针对Python中万物皆对象的理解,对Python的类型、对象体系做一个整体的梳理。

在Python中,一切皆为对象,一个整数是一个对象,一个字符串也是一个对象,基本类型(如int)也是对象。Python不再区别对待基本类型和对象,所有的基本类型内部均由对象实现。

>>> a = int
>>> b = 1
>>> id(a)
140734789683952
>>> id(int)
140734789683952
>>> a
<class 'int'>
>>> id(b)
2421963817200
>>> id(1)
2421963817200
>>> b
1

1 类型对象和实例对象

Python中的类型是一种对象,称为类型对象。整数类型、字符串类型,以及我们通过class关键字定义的自定义类型也是一个对象。

通过类实例化可以得到一个实例化对象,称为实例对象

2 类型、对象体系

2.1 元类型type

前面我们提到:Python中的类型是一种对象,称为类型对象。那么类型对象的类型又是什么呢?

>>> type(int)
<class 'type'>
>>> int.__class__
<class 'type'>

可以看到,类型的类型是type,我们称之为元类型,但是这个类型比较特殊,它的实例对象是类型对象。此外,Python中还有一个特殊的类型object,所有其他类型都继承于object,即object是所有类型的基类。

图示如下:

2.2 自定义类型

除了Python的内置类型,我们自定义一个类型MyClass,同样地,可以得到:

2.3 自定义类型子类

再定义一个类型MySubClass,该类型为MyClass的子类:

2.4 type和object的关系

在上述示例中,我们描述了不同对象、类型之间的继承、类型关系,但是对于两个特殊的类型type和object的关系并没有指出,我们先来打印看一下:

>>> type(type)
<class 'type'>
>>> type(object)
<class 'type'>
>>> type.__base__
<class 'object'>
>>> object.__base__
>>> print(object.__base__)
None

可以看到:object的类型也是type,type本身的类型也是type;而type的父类也是所有对象的父类——object,而object本身没有父类。由此我们可以归纳出:

object是所有类型的基类(除了它自己),本质上是一种类型,其类型是type,同时也是type的基类;

type是所有类型的类型,本质上是一种类型,其类型是它自己,也是object的类型;

注:object本身不能有基类,这是因为——对于存在继承关系的类,成员属性和成员方法查找需要回溯继承链,不断查找基类。因此,继承链必须有一个终点,不然就会死循环。

最后我们把type和object的关系补充进来:

3 可变对象与不可变对象

可变对象在创建之后,其值可以修改;不可变对象在创建之后,其值不可以进行修改。

以Python中的整数对象为例:整数类型是不可变类型,整数对象是不可变对象。“修改整数对象”时,Python将以新值创建一个新对象,变量名与新对象进行绑定,旧对象如果没有其他引用,则会被释放(通过“小整数池”进行创建回收优化,具体后续介绍,这里先按下不表,后续会补充)。

图示如下:

以Python中的列表对象为例:列表类型是可变类型,列表对象是可变对象。列表对象内部会维护一个动态数组,存储元素对象的指针,列表对象再增减对象的时候,会修改该数组,而列表对象的“头部”(后续会详细介绍)会保持不变:

4 变长对象和定长对象

定长对象:对象的内存大小一定

边长对象:同一类型,不同对象会有不同的大小

通过sys.getsizeof()可以查看一个对象的大小:

>>> import sys
>>> a = 1
>>> b = 1111111111111111111111111111111111111111111111111111111111
>>> c = 1.0
>>> d = 1.00000000000000000000000000000000000000000000000000000001
>>> sys.getsizeof(a)
28
>>> sys.getsizeof(b)
52
>>> sys.getsizeof(c)
24
>>> sys.getsizeof(d)
24

整数对象是变长对象:固定位数的整数能够表示的范围是有限的,故整数对象会随着自身的数值大小而改变自身内存大小。在Python中采用了类似C++中大整数类的思路实现整数对象,通过串联多个普通32位整数来支持更大的数值范围(详细源码后续介绍)。

浮点数对象是定长对象:根据机组的知识,我们用32位表示单精度浮点数,用64位表示双精度浮点数,它们都是定长的。在Python中,浮点数背后是由一个double来实现的,就算表示很大的数,浮点数对象的大小也不变(这样做的代价是牺牲了精度)。当然,浮点数也是有大小限制的,可以思考下:我们通过float()将一个很大的int转化为float时,是否会报错?Python底层是否做了相应的判断呢?

5 补充

变量名:我们创建对象时会为对象分配对应的内存空间,那么我们将变量名和对象绑定时,变量又是如何存储的呢?

详见Python源码学习笔记:Python作用域与名字空间

以上就是Python万物皆对象理解及源码学习的详细内容,更多关于Python对象的资料请关注我们其它相关文章!

(0)

相关推荐

  • Python浅复制中对象生存周期实例分析

    本文实例讲述了Python浅复制中对象生存周期.分享给大家供大家参考,具体如下: Python的浅复制以及深复制我了解的并不多,我不清楚shutil中的copy1和copy2是不是算是浅复制和深复制?这两个操作,一个是文件属性重建,还有一个是文件属性不变.不知道对象的复制是否可以以此类比? 在复制之前,为了能够观看一下GC的执行,定义一个特殊的类和对象.测试代码如下: class Demo: def __del__(self): print("Removing{0}".format(i

  • Python对象的生命周期源码学习

    目录 思考: 1 C API 2 对象的创建 2.1 两种创建对象的方式 2.2 由类型对象创建实例对象 3 对象的多态性 4 对象的行为 5 引用计数 思考: 当我们输入这个语句的时候,Python内部是如何去创建这个对象的? a = 1.0 对象使用完毕,销毁的时机又是怎么确定的呢? 下面,我们以一个基本类型float为例,来分析对象从创建到销毁这整个生命周期中的行为. 1 C API Python是用C写的,对外提供了API,让用户可以从C环境中与其交互,并且Python内部也大量使用了这

  • Python学习之面向对象编程详解

    目录 什么是面向对象编程(类) 类的关键字-class 类的定义与使用 类的参数-self self的解析与总结 类的构造函数 构造函数的创建方法 关于对象的生命周期 什么是面向对象编程(类) 利用(面向)对象的(属性和方法)去进行编码的过程即面向对象编程 自定义对象数据类型就是面向对象中的类(class)的概念 类的关键字 - class class 关键字用来声明类,类的名称首字母大写,多单词的情况下每个单词首字母大写(即驼峰命名法).在我们一开始学习 Python 的时候说过,要尽量避免使

  • Python中for循环可迭代对象迭代器及生成器源码学习

    目录 问题: 1. 迭代 1.1 可迭代对象Iterable 1.2 迭代器Iterator 1.3 for循环 1.3.1 iter()方法和next()方法 1.3.2 iter()和__iter__() 1.3.3 next()和__next__() 1.3.4 自定义类实现__iter__()和__next__() 1.3.5 探究for循环 2 生成器 2.1 获取生成器 2.2 next(生成器) 2.3 生成器和迭代器 2.4 生成器解析式 问题: 之前在学习list和dict相关

  • Python万物皆对象理解及源码学习

    目录 万物皆对象 1 类型对象和实例对象 2 类型.对象体系 2.1 元类型type 2.2 自定义类型 2.3 自定义类型子类 2.4 type和object的关系 3 可变对象与不可变对象 4 变长对象和定长对象 5 补充 万物皆对象 这篇博客的内容主要是针对Python中万物皆对象的理解,对Python的类型.对象体系做一个整体的梳理. 在Python中,一切皆为对象,一个整数是一个对象,一个字符串也是一个对象,基本类型(如int)也是对象.Python不再区别对待基本类型和对象,所有的基

  • Python虚拟机栈帧对象及获取源码学习

    目录 Python虚拟机 1. 栈帧对象 1.1 PyFrameObject 1.2 栈帧对象链 1.3 栈帧获取 2. 字节码执行 Python虚拟机 注:本篇是根据教程学习记录的笔记,部分内容与教程是相同的,因为转载需要填链接,但是没有,所以填的原创,如果侵权会直接删除.此外,本篇内容大部分都咨询了ChatGPT,为笔者解决了很多问题. 问题: 在Python 程序执行过程与字节码中,我们研究了Python程序的编译过程:通过Python解释器中的编译器对 Python 源码进行编译,最终获

  • Python对象的底层实现源码学习

    目录 1. PyObject:对象的基石 2. PyVarObject:变长对象的基础 2.1 浮点对象 2.2 列表对象 3. PyTypeObject:类型的基石 4. PyType_Type:类型的类型 5. PyBaseObject_Type:类型之基 6. 补充 在“Python源码学习笔记:Python万物皆对象”中,我们对Python的对象类型体系有了一定的认识,这篇博客将从源码层面来介绍Python中万物皆对象的底层实现. 1. PyObject:对象的基石 在Python解释器

  • Python源码学习之PyType_Type和PyBaseObject_Type详解

    PyType_Type和PyBaseObject_Type PyObject和PyTypeObject内容的最后指出下图中对实例对象和类型对象的理解是不完全正确的, 浮点类型对象全局唯一,Python在C语言层面实现过程中将其定义为一个全局静态变量,定义于Object/floatobject.c中,命名为PyFloat_Type. PyTypeObject PyFloat_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "float&quo

  • Python内建类型int源码学习

    目录 1 int对象的设计 1.1 PyLongObject 1.2 整数的布局 1.3 小整数静态对象池 1.4 示例 2 大整数运算 2.1 整数运算概述 2.2 大整数运算处理过程 1.long_add()源码: 2.绝对值加法x_add() 3 其他 大整数转float溢出 “深入认识Python内建类型”这部分的内容会从源码角度为大家介绍Python中各种常用的内建类型. 问题:对于C语言,下面这个程序运行后的结果是什么?是1000000000000吗? #include <stdio

  • 深入理解vue-class-component源码阅读

    vue-class-component是vue作者尤大推出的一个支持使用class方式来开发vue单文件组件的库.但是,在使用过程中我却发现了几个奇怪的地方. 首先,我们看一个简单的使用例子: // App.vue <script> import Vue from 'vue' import Component from 'vue-class-component' @Component({ props: { propMessage: String } }) export default clas

  • python 爬取疫情数据的源码

    疫情数据 程序源码 // An highlighted block import requests import json class epidemic_data(): def __init__(self, province): self.url = url self.header = header self.text = {} self.province = province # self.r=None def down_page(self): r = requests.get(url=url

  • Python源码学习之PyObject和PyTypeObject

    前言 Python是C语言实现的,因此Python对象在C语言层面应该是一个结构体 ,组织对象占用的内存. 不同类型的对象,数据及行为均可能不同,因此可以大胆猜测:不同类型的对象由不同的结构体表示. 对象也有一些共性,比如每个对象都需要有一个引用计数,用于实现垃圾回收机制.因此,还可以进一步猜测:表示对象的结构体有一个公共头部. 一. 实例对象的基石-PyObject和PyVarObject PyObject和PyVarObject本质上是对象的头部信息. 1.1 PyObject结构体 Pyt

  • 深入剖析理解AsyncGetCallTrace源码底层原理

    目录 前言 源码实现 核心数据结构 函数申明 AsyncGetCallTrace 实现 pd_get_top_frame_for_signal_handler 实现 pd_get_top_frame 实现 forte_fill_call_trace_given_top 实现 总结 前言 AsyncGetCallTrace 是由 OracleJDK/OpenJDK 内部提供的一个函数,该函数可以在 JVM 未进入 safepoint 时正常获取到当前线程的调用栈(换句话说,使用该函数获取线程栈时,

随机推荐