五、从PyIntObject出发

Python源码剖析(三)整数对象 1 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]; 阅读详情

1.初识PyIntObject

本节要说的内容是“整数”,我们来看看这个PyInt_Type变量,这个变量里面大量的元信息是我们要关注的。它描述了一个整数对象。

[intobject.c]
PyTypeObject PyInt_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "int",
    sizeof(PyIntObject),  //对象占用内存大小
    0,
    (destructor)int_dealloc,                    /* tp_dealloc */ //对象析构
    (printfunc)int_print,                       /* tp_print */  //打印PyIntObject对象
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    (cmpfunc)int_compare,                       /* tp_compare */  //比较操作
    (reprfunc)int_to_decimal_string,            /* tp_repr */
    &int_as_number,                             /* tp_as_number */  //一个函数域,描述作为一个number该有的行为
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    (hashfunc)int_hash,                         /* tp_hash */ //获得HASH值
    0,                                          /* tp_call */
    (reprfunc)int_to_decimal_string,            /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_INT_SUBCLASS,          /* tp_flags */
    int_doc,                                    /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    0,                                          /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    int_methods,                                /* tp_methods */
    0,                                          /* tp_members */
    int_getset,                                 /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
    0,                                          /* tp_descr_get */
    0,                                          /* tp_descr_set */
    0,                                          /* tp_dictoffset */
    0,                                          /* tp_init */
    0,                                          /* tp_alloc */
    int_new,                                    /* tp_new */
    (freefunc)int_free,                         /* tp_free */
};

各个函数的实现都在intobject.c中,可自行查看。

如:加法代码:

[intobject.h]
#define PyInt_AS_LONG(op) (((PyIntObject *)(op))->ob_ival)

[intobject.c]
#define CONVERT_TO_LONG(obj, lng)               \
    if (PyInt_Check(obj)) {                     \
        lng = PyInt_AS_LONG(obj);               \
    }                                           \
    else {                                      \
        Py_INCREF(Py_NotImplemented);           \
        return Py_NotImplemented;               \
    }

static PyObject *
int_add(PyIntObject *v, PyIntObject *w)
{
    register long a, b, x;
    CONVERT_TO_LONG(v, a);
    CONVERT_TO_LONG(w, b);
    /* casts in the line below avoid undefined behaviour on overflow */
    x = (long)((unsigned long)a + b);
    //溢出检查
    if ((x^a) >= 0 || (x^b) >= 0)
        return PyInt_FromLong(x);
    return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *)w);
}

2.PyIntObject的创建和维护

对象创建三种途径:

[intobject.h]
PyAPI_FUNC(PyObject *) PyInt_FromLong(long);
PyAPI_FUNC(PyObject *) PyInt_FromSize_t(size_t); //实际上调用的是PyInt_FromFloat
PyAPI_FUNC(PyObject *) PyInt_FromSsize_t(Py_ssize_t);//实际上调用的是PyInt_FromFloat

我们主要讨论:PyInt_FromLong

------------------------------------割,以下讨论整数的存储形式,及方案------------------------------------

小整数对象使用对象池技术:Python直接将这些整数对应的PyIntObject缓存在内存中,其指针放在small_ints中

[intobject.c]
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS           257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS           5
#endif
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
/* References to small integers are saved in this array so that they
   can be shared.
   The integers that are saved are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
#endif

大整数对象Python运行环境将提供一块内存空间,这些内存空间由这些大整数轮流使用。

[intobject.c]
#define BLOCK_SIZE      1000    /* 1K less typical malloc overhead */
#define BHEAD_SIZE      8       /* Enough for a 64-bit pointer */
#define N_INTOBJECTS    ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject))

struct _intblock {
    struct _intblock *next;
    PyIntObject objects[N_INTOBJECTS];
};

typedef struct _intblock PyIntBlock;

static PyIntBlock *block_list = NULL;
static PyIntObject *free_list = NULL;

通用整数对象池的创建:

[intobject.c]
static PyIntObject *
fill_free_list(void)
{
    PyIntObject *p, *q;
    /* Python's object allocator isn't appropriate for large blocks. */
    p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock));//申请一块block的内存
    if (p == NULL)
        return (PyIntObject *) PyErr_NoMemory();
    ((PyIntBlock *)p)->next = block_list;//连接到已有的block_list中,大家非常熟悉的头接法
    block_list = (PyIntBlock *)p; //重新把block_list置为头部
    /* Link the int objects together, from rear to front, then return
       the address of the last int object in the block. */
    p = &((PyIntBlock *)p)->objects[0];
    q = p + N_INTOBJECTS;
    while (--q > p)
        Py_TYPE(q) = (struct _typeobject *)(q-1);
    Py_TYPE(q) = NULL;
    return p + N_INTOBJECTS - 1;
}

[ctypes.h]
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)

效果如图:

通用整数对象池的使用:

[intobject.c]
static void
int_dealloc(PyIntObject *v)
{
    if (PyInt_CheckExact(v)) {
        Py_TYPE(v) = (struct _typeobject *)free_list;
        free_list = v;
    }
    else
        Py_TYPE(v)->tp_free((PyObject *)v);
}

小整数对象池的创建:

[intobject.c]
int
_PyInt_Init(void)
{
    PyIntObject *v;
    int ival;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
    for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) {
          if (!free_list && (free_list = fill_free_list()) == NULL)
                    return 0;
        /* PyObject_New is inlined */
        v = free_list;
        free_list = (PyIntObject *)Py_TYPE(v);
        PyObject_INIT(v, &PyInt_Type);
        v->ob_ival = ival;
        small_ints[ival + NSMALLNEGINTS] = v;
    }
#endif
    return 1;
}

创建后效果如图:事实上,小整数对象也是生存在block_list所维护的内存上


------------------------------------割,以上讨论整数的存储形式,及方案------------------------------------

现在存储有了,让我们来看看PyInt_FromLong,具体如何创建一个PyIntObject

[intobject.c]
PyObject *
PyInt_FromLong(long ival)
{
    register PyIntObject *v;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
//如果小整数对象池被激活,尝试使用小整形对象池
  if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
        v = small_ints[ival + NSMALLNEGINTS];
        Py_INCREF(v);
#ifdef COUNT_ALLOCS
        if (ival >= 0)
            quick_int_allocs++;
        else
            quick_neg_int_allocs++;
#endif
        return (PyObject *) v;
    }
#endif
//木有办法了,大整形,只好用通用的整数对象池了
//对象池木有空间,新申请
    if (free_list == NULL) {
        if ((free_list = fill_free_list()) == NULL)
            return NULL;
    }
    /* Inline PyObject_New */
    v = free_list;
    free_list = (PyIntObject *)Py_TYPE(v);
    PyObject_INIT(v, &PyInt_Type);
    v->ob_ival = ival;
    return (PyObject *) v;
}
Python学习笔记一:PyIntObject内存池机制 PyIntObject内存池机制                   -----------------   仅以图片简单说明,不会做过多啰嗦 1. 已分配空间无剩余,新建PyIntObject对象。         此时创建新的PyIntBlock存储块加入对象存储池,由block_list全局指针维护(block_list始终指向最新加入的PyIntBlock);其中,新建的PyIntB... 阅读详情

相关推荐

C# NX二次开发:两种过滤器设置方案的实战解析与场景适配

本文深入解析C# NX二次开发中的两种过滤器设置方案:AddFilterHandler回调与MaskTriple属性设置。通过实战案例对比其性能差异与适用场景,帮助开发者根据需求选择最优方案,提升NX插件开发效率与交互体验。特别针对BlockStyler集成场景提供专业建议,是NX二次开发者的实用指南。

weixin_33739646的博客 844

python function terminated_python install zbar错误:安装脚本已退出,错误为:命令'gcc'失败,退出状态为1...

环境:pyenv versionssystem2.7.13* 3.4.3 (set by /home/foo/.pyenv/version)3.4.3/envs/venv343venv343Searching for zbarReading https://pypi.python.org/simple/zbar/Downloading https://files.pythonhosted.org/...

weixin_39842682的博客 471

SAP PP未清生产订单关闭物料退料、新工单发料批量处理

( werks = '1001' lgort = 'A004' lgobe = '组装-成品组装' )( werks = '1002' lgort = 'C006' lgobe = '组装-二车间' )( werks = '1002' lgort = 'C007' lgobe = '组装-二车间' )( werks = '1001' lgort = 'A007' lgobe = '组装-MS' )( werks = '1001' lgort = 'A008' lgobe = '组装-GW' )

dingqing86的专栏 1193

CentOS安装zbar及pyzbar

CentOS安装zbar方法一方法二方法三 方法一 sudo yum update sudo yum install python3-devel sudo yum install zbar-devel sudo yum install zbar pip install pyzbar 不知为何我执行上面指令出现:No package zbar/zbar-devel available. 直接执行pip install pyzbar报错: Building wheel for zbar (setup.p

红叶谷 wsp_1138886114的博客 3823

【技术分享】语音多模态LLM越狱

语音多模态LLM越狱攻击作为一种新兴安全威胁,揭示了多模态模型在语音输入场景下的脆弱性。尽管已有多种攻击方法被提出,但其具体实现步骤、防御措施的有效性及行业影响等问题仍需进一步探索[9]。未来研究应聚焦于改进模型架构、开发针对性防御策略,并评估语音输入越狱攻击的实际危害。只有通过全面理解这些挑战,才能为多模态智能系统的安全性提供更可靠的保障。说到语音多模态LLM越狱的具体实现步骤,这其实是一个复杂且多层次的过程🧐。首先,攻击者需要深入分析目标模型的响应模式和安全机制,找出可能的漏洞点。

qq_29883477的博客 1261

【软件介绍】RVC本地部署使用方法

【摘要】RVC是一款功能强大的开源语音转换工具,具有实时处理、多音效选择、高质量音频处理等特点。文章详细介绍了RVC的安装与使用方法:1)配置Python环境;2)根据电脑系统选择对应安装包解压;3)启动程序进入浏览器操作界面。重点讲解了声音克隆的关键步骤:建议使用短音频素材,选择合适训练方法(推荐pm或rmvpe),设置100次训练轮数,生成的模型文件存入weights文件夹。最后通过上传音频即可实现声音克隆。操作过程需注意保持程序运行状态,并提供了相关资源下载地址。

心动的那一刻,记忆便盛开了花 2983

python整数运算_深入 Python (6) 整数对象的数学运算

整数的基本运算上一节讲到,在 PyLong_Type 中定义了整数类型的各种属性,比如整数类型的名称 “int”。整数对象最常用的是一些数学运算,整数对象当然也是支持这些方法的,它们定义在:// Object/longobject.c:5632PyTypeObject PyLong_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"int", ...

weixin_39606396的博客 586

LLVM实战:如何用Clang+LLVM打造你的第一个C++编译器(附完整配置步骤)

本文详细介绍了如何使用Clang+LLVM构建C++编译器的完整配置步骤,从环境准备到编译流程剖析,再到调试与优化技巧。通过实战指南,帮助开发者深入理解LLVM编译器框架的工作原理,并掌握交叉编译与性能分析等高级功能。

sprite的博客 748

python bytes 操作_《深度剖析CPython解释器》6. 解密Python中bytes对象的底层实现,以及相关操作...

楔子不少编程语言中的"字符串"都是使用字符数组(或者称字符序列)来表示,比如C语言和go语言就是这样。char name[] = "komeiji satori";一个字节最多能表示256个字符,所以对于英文来说足够了,因此一个英文字符占一个字节即可,然而对于那些非英文字符便力不从心了。因此为了表示这些非英文编码,于是多字节编码应运而生----通过多个字节来表示一个字符。但由于原始字节序列不维护编...

weixin_39611072的博客 953

Xilinx SDK工程编译、链接、调试注意事项

1、添加工程 启动SDK时选取workspace,如下图所示: 对应的workpace文件夹中会生成如下几个文件: 如果当前workspace是首次加载工程,SDK会进入启动界面 点击Import Project,导入已有工程 点击Browse,添加工程路径,一个完整的工程包含一个bsp文件夹,一个HW文件夹,和一个src文件夹(添加C功能函数) 点击Fini...

Autumn_He的博客 1万+

VC Spyglass CDC实战:从TCL脚本到SDC约束的完整避坑指南

本文是一份针对数字IC验证工程师的VC Spyglass CDC实战指南。文章详细阐述了从TCL脚本环境搭建、SDC约束编写到典型CDC违规(如SETUP_PORT_UNCONSTRAINED)诊断与修复的完整流程,旨在帮助读者高效避坑,深入理解工具逻辑,从而完成可靠的时钟域交叉验证。

go5gopher的博客 385

Python内部机制-PyIntObject对象

Python int对象的实现Python内部关于int对象的实现在我之前的两篇文章中其实已经简单的介绍过,本文会前面的基础上更加深入的分析int对象的内部实现,以及Python对int对象进行优化而采用的缓存技术等等.首先还是来看看int对象在C层面的一个数据结构吧.typedef struct { PyObject_HEAD lo

zyfforlinux 4103

SEATA安装使用

springcloudalibaba集成seata分布式事务、seata持久化

原名又逢乱世。不要放下学习的脚步,毕竟比天天打牌、钓鱼、打游戏更能从内在充实自己。 2370

python源码剖析—— 初识 PyIntObject 对象

其次,Python内部也大量的使用整数对象,我们在自己的代码中也会有大量的创建销毁整型对象的操作,因此单独的维护整形对象并对其申请内存和释放内存是不现实的。另一个是干啥的稍微一想就能想到:这个 block 链表维护的是一整块block,是block级别的,我要使用的是。构成了一个整数系统,其下有两个“部门”,一个是静态对象池,一个是动态缓冲池,两个池的管理使用两个不同级别的指针。注意,新申请的 block 在链表头,这样做的原因是考虑到链表的插入效率。的操作,像前面说的,定义在该类型对象的函数指针中。

莫彩的博客 494

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

PyIntObject 对象

1、PyIntObject 对象 [intobject.h] typedef struct { PyObject_HEAD long ob_ival; } PyIntObject PyIntObject是一个不可变(immutable)对象。Python内部也大量的使用整数对象,我们在自己的代码中也会有大量的创建销毁整型对象的操作,因此单独的维护整形对象并对其申请内存和释放内存是不现实的。Python给出的解决方案是将整形对象通过一定的结构连接在一起的整数对象系统:整数对象池,一个整形对象的缓冲池机制。对象

Code Writers 397

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

[Python源码学习]之整数类型PyIntObject

在Python2中,有 PyIntObject 和 PyLongObject 两种整数类型,在Python3中,前者并入后者。本文是Python2 相关的内容。 PyIntObject 整数对象定义在头文件 Include/intobject.h 中,它表示一个(长)

1+1=10 3113

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

PyIntObject的对象池技术太可怕了~

最近在读《Python源码剖析》,只是看到PyIntObject的对象池技术而已,根据书中的讲解及源码可知:一旦系统中的某块内存被Python申请用于整数对象,那么这块内存在Python进程结束之前,将永远不会得到释放。   这样一句话实在太可怕了,于是做了个小小的实验: 假设sizeof(PyIntObject) = 12byte,那么1GB = 1024 * 1024 * 1024 / ...

zhuxianfeng的专栏 176

int转long python_【系列】Python源码剖析(base 2.7.18)Note之PyIntObject对象

2.1 PyIntObject对象对象的分类除了可以分类为定长与变长对象之外,还可以分为可变(mutable)与不可变(immutable)。PyIntObject是不可变对象,即创建了一个PyIntObject对象之后就再也不能改变对象的值了。除PyIntObject之外,其他具有此特性的对象还有字符串对象等。运行时的整数对象会频繁被访问,因此设计了整数对象池缓冲机制来使得整数对象的使用更高效。...

weixin_28706923的博客 249

int定义源码 python_Python源代码--整数对象(PyIntObject)的内存池

【背景】原文链接:http://blog.youkuaiyun.com/ordeder/article/details/25343633Python整数对象是不可变对象,什么意思呢?比如运行例如以下python语句>>>a = 1023>>>a = 1024>>>b = a>>>c = 1024>>>d = 195&gt...

weixin_39601088的博客 204

python dll void指针_Python源码学习笔记(三)PyIntObject

PyIntObject就是python中int在虚拟机中的实体,我们来看一下它长什么样。// file: intobject.h typedef struct { PyObject_HEAD long ob_ival; } PyIntObject;可以看到,其实PyIntObject的结构很简单,就是在PyObject的基础上加了一个long。而这个ob_ival就是这个int对象...

weixin_39996762的博客 270

对PyIntObject的认识(对象池)

Int 可以说是Python里最简单的对象了,我们也应该可以想象的到,它应该是把C里面的int或者long包装了一下,那么,仅仅是包装一下而已吗?下面是PyIntObject 的定义 typedef struct { PyObject_HEAD long ob_ival; } PyIntObject; 确实非常简单,可以看到,PyIntObject的头部是PyObject

wangyuquanliuli的专栏 1410

python 整数对象PyIntObject的创建和维护

整数对象的创建有以下几种,并非书中所述3种 从源码中看到最终都是调用PyInt_FromLong,书中写的PyInt_FromFloat,需要注意这点。 所以重点阅读函数PyInt_FromLong: 方便用户直接取用,小整数对象池是python运行是就必须存在的。按照这个思路,那么小整数对象池的初始化就应该在PyIntObject的_init中,在源码中也证实了这个思路:...

Y21233的博客 332

[笔记]Python的整数对象:PyIntObject

一般没有特指,参考的是Python 2.7.2的源码。 在intobject.h的开头就有英文注释,对PyIntObject进行了一下简单介绍。 原文如下: /* PyIntObject represents a (long) integer.  This is an immutable object; an integer cannot change its value aft

JasonLee的专栏 5429

Python源码--整数对象(PyIntObject)的内存池

由于python中的整数对象记录的整数值是不可变的,所以在名字a的值不断变化的过程中,就就涉及到了多次对象的创建和销毁。所以python为整数对象申请空间进行了两种优化: 优化1:为通用整数对象存储池 优化2:为小整数对象构建特殊的缓冲 PyIntObject分为小整数对象[-5~257)及大整数对象。小整数对象在py启动过程中初始化,从而实现小整数对象的缓存,缓冲中的小整数对象在py运行期间不会被销毁。 大整数对象需要程序员动态申请,对象在运行过程中根据ob_refcnt引

ordeder的专栏 4533
上一篇: 四、再谈PyTypeObject
下一篇: 低端N卡完美硬解1080p的WMV3
debugm
博客等级 码龄16年 13粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值