深度解密 Python 的浮点数是怎么实现的?

开发 前端
假设我们要将两个浮点数相加,相信你已经知道解释器会如何做了?通过 PyFloat_AsDouble 将两个浮点数的 ob_fval 抽出来,然后相加,最后再根据相加的结果创建一个新的 PyFloatObject 即可。

楔子

从现在开始,我们就来分析 Python 的内置对象,看看它们在底层是如何实现的。但说实话,我们在前面几篇文章中介绍对象的时候,已经说了不少了,不过从现在开始要进行更深入的分析。

除了对象本身,还要看对象支持的操作在底层是如何实现的。我们首先以浮点数为例,因为它是最简单的,没错,浮点数比整数要简单,至于为什么,等我们分析整数的时候就知道了。

浮点数的底层结构

要想搞懂浮点数的实现原理,就要知道它在底层是怎么定义的,当然在这之前我们已经见过它很多遍了。

// Include/cpython/floatobject.h
typedef struct {
    PyObject_HEAD
    double ob_fval;
} PyFloatObject;

它包含了一个公共头部 PyObject 和一个 double 类型的 ob_fval 字段,毫无疑问这个 ob_fval 字段负责存储浮点数的具体数值。

我们以 e = 2.71 为例,底层结构如下。

图片图片

还是很简单的,每个对象在底层都是由结构体表示的,这些结构体中有的字段负责维护对象的元信息,有的字段负责维护具体的值。比如这里的  2.71,总要有一个字段来存储 2.71 这个值,而这个字段就是 ob_fval。所以浮点数的结构非常简单,直接使用一个 C 的 double 来维护。

假设我们要将两个浮点数相加,相信你已经知道解释器会如何做了?通过 PyFloat_AsDouble 将两个浮点数的 ob_fval 抽出来,然后相加,最后再根据相加的结果创建一个新的 PyFloatObject 即可。

浮点数是怎么创建的

下面来看看浮点数是如何创建的,在前面的文章中,我们说对象可以使用对应的特定类型 API 创建,也可以通过调用类型对象创建。

调用类型对象 float 创建实例对象,解释器会执行元类 type 的 tp_call,它指向了 type_call 函数。然后 type_call 内部会先调用类型对象(这里是 float)的 tp_new 为其实例对象申请一份空间,申请完毕之后对象就已经创建好了。然后再调用 tp_init,并将实例对象作为参数传递进去,进行初始化,也就是设置属性。

但是对于 float 来说,它内部的 tp_init 字段为 0,也就是空。

图片图片

这就说明 float 没有 __init__,因为浮点数太过简单,只需要一个 tp_new 即可。我们举个例子:

class Girl1:

    def __init__(self, name, age):
        self.name = name
        self.age = age

# __new__  负责开辟空间、生成实例对象
# __init__ 负责给实例对象绑定属性

# 但其实 __init__ 所做的工作可以直接在 __new__ 当中完成
# 换言之有 __new__ 就足够了,其实可以没有 __init__
# 我们将上面的例子改写一下
class Girl2:

    def __new__(cls, name, age):
        instance = object.__new__(cls)
        instance.name = name
        instance.age = age
        return instance

g1 = Girl1("古明地觉", 16)
g2 = Girl2("古明地觉", 16)
print(g1.__dict__ == g2.__dict__)  # True

我们看到效果是等价的,因为 __init__ 负责给 self 绑定属性,而这个 self 是 __new__ 返回的。那么很明显,我们也可以在 __new__ 当中绑定属性,而不需要 __init__。

责任编辑:武晓燕 来源: 古明地觉的编程教室
相关推荐

2020-09-15 12:57:46

C 语言浮点数内存

2023-07-05 08:00:58

Redis数据库

2018-08-24 10:16:23

内存浮点数存储

2017-10-16 10:42:27

前端JavaScript浮点数

2011-05-25 14:10:38

浮点数

2020-10-12 06:38:08

存储定点数

2010-07-22 17:39:44

2015-12-02 10:21:34

JavaScript浮点数精度调整

2010-01-15 15:21:35

C++

2021-10-19 14:04:28

C++类型数字

2009-05-19 10:10:01

Oracle时间加减时间操作

2024-07-11 15:50:36

2024-08-23 08:43:08

2021-11-15 09:32:06

浮点面试Java

2022-06-15 15:44:21

无损数据压缩鸿蒙

2022-09-16 07:24:12

Python 的四舍

2024-09-18 13:49:42

2024-09-05 10:49:42

2024-08-02 11:33:49

2023-11-23 19:30:35

Python编程语言
点赞
收藏

51CTO技术栈公众号