Python源码剖析(三)整数对象 1

bilibili视频讲解:https://space.bilibili.com/431392724
用户名:平凡的久月

Python3中用LongObject表示整型Number,Python2中用IntObject和LongObject表示整型Number。

1. PyLongObject 概述

在Python中没有对象能被完全被声明为一个PyObject,但每一个指向Python的对象的指针均能够被视为一个PyObject* 指针。

1.1 Python3中一个整型数字占多少个字节?

struct _longobject {
    PyObject_VAR_HEAD  
    digit ob_digit[1];
};

typedef uint32_t digit;

#define PyObject_VAR_HEAD  PyVarObject ob_base;

typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

// 如果定义了Py_TRACE_REFS的话,这个结构将可以支持双向列表,并且所有堆中的活动均在这个列表中
// 因为在 release模式 下没有定义Py_TRACE_REFS,所以可以忽略这个宏或者理解为null
#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;

#define _PyObject_EXTRA_INIT 0, 0,

#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif

现在主要来研究Py_ssize_t,先说结论:Py_ssize_t在64位系统中是64位的int,而32位系统是_W64,所以Py_ssize_t的本质为一个8个字节的int类型。

// Include/pyport.h
/* Py_ssize_t is a signed integral type such that sizeof(Py_ssize_t) ==
 * sizeof(size_t).  C99 doesn't define such a thing directly (size_t is an
 * unsigned integral type).  See PEP 353 for details.
 */
#ifdef HAVE_SSIZE_T
typedef ssize_t         Py_ssize_t;
#elif SIZEOF_VOID_P == SIZEOF_SIZE_T
typedef Py_intptr_t     Py_ssize_t;
#else
#   error "Python needs a typedef for Py_ssize_t in pyport.h."
#endif

关于HAVE_SSIZE_T,对于HAVE_SSIZE_T的默认定义为 1 。

关于ssize_t,即我们默认下,根据平台将ssize_t的类型设置为__int64或者_W64

// 这两项定义在 PC/pyconfig.h 中,这里非常重要!!!
#ifdef MS_WIN64
typedef __int64 ssize_t;
#else
typedef _W64 int ssize_t;
#endif
#define HAVE_SSIZE_T 1

终上所述,PyLongObject可以等价为下列表达,至少为24个字节。同时·,也可以看出LongObject是一个变长对象(obsize决定)。

struct _longobject {
    _PyObject_HEAD_EXTRA   // release模式下为null
    Py_ssize_t ob_refcnt;          // 8个字节
    struct _typeobject *ob_type;   // 8个字节(指针与系统寻址能力有关,64位系统则为8个字节)
    Py_ssize_t ob_size;            // 8个字节
    digit ob_digit[1];     // 以四个字节为间距增加,可以没有(ob_size=0)
};

1.2 整数对象池

整数对象的缓冲池机制

面向特定对象的缓冲池机制也是Python语言实现时的核心设计策略之一

1.3 一般对象的创建与运行

对于PyLongObject,与对象相关的原信息保存在与对象对应的类型对象中,其对应PyLong_Type。

整型对象创建过程概括:实例化对象(PyLongObject) --> PyLong_Type(PyTypeObject) --> PyType_Type(PyTypeObject)

先看基本Object在这里插入图片描述

可以看出,各种对象都拥有相同的对象头部,因此只需要一个PyObject *指针就可以引用任意一个对象,而不论该对象实际是一个什么对象。这也就是 PyObject是对象机制基石 的原因。

再看对象的创建过程(以整型对象为例进行一般过程概括,其实整型对象的创建稍有区别,后面会详细说明)在这里插入图片描述

  1. 调用类型对象的tp_new(int(PyLongObject) --> PyLong_Type(PyTypeObject));

  2. 如果上述tp_new=null,则根据tp_base找到指定的基类;

  3. 调用基类中的tp_new(所有类都是以object类为基类的,所以总是能找到一个非空的tp_new);

  4. 访问类型对象PyLong_Type中的tp_basicsize信息,完成内存申请操作(这个信息记录这一个整数对象应该占用多大内存);

  5. 调用tp_init完成初始化对象的工作。

最后看看运行时对象与类型的关系在这里插入图片描述

1.4 PyLongObject对象的元信息

根据源码尝试自己回答以下问题

  1. 两个整数对象如何比较大小?(longobject.c)

  2. 加法操作如何实现?

    // longobject.c
    /* Add the absolute values of two integers. */
    
    static PyLongObject *
    x_add(PyLongObject *a, PyLongObject *b)
    {
    // ......
    }
    
  3. 如何理解 long_as_number 与 PyNumberMethods的关系?

    // object.h
    #ifndef Py_LIMITED_API
    typedef struct {
        /* Number implementations must check *both*
           arguments for proper type and implement the necessary conversions
           in the slot functions themselves. */
    
        binaryfunc nb_add;
        // .......
    } PyNumberMethods;
    
    // longobject.h
    static PyNumberMethods long_as_number = {
        (binaryfunc)long_add,       /*nb_add*/
        (binaryfunc)long_sub,       /*nb_subtract*/
        0,                          /*nb_reserved*/
       // ......
    };
    
  4. 如何通过加法操作理解整型对象时不可变对象(immutable)?

    结合返回值进行考虑

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值