`
jinvasshole
  • 浏览: 792051 次
文章分类
社区版块
存档分类
最新评论

【Python旧时笔记 二】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 after creation.

There are functions to create new integer objects, to test an object
for integer-ness, and to get the integer value. The latter functions
returns -1 and sets errno to EBADF if the object is not an PyIntObject.
None of the functions should be applied to nil objects.

The type PyIntObject is (unfortunately) exposed here so we can declare
_Py_TrueStruct and _Py_ZeroStruct in boolobject.h; don't use this.
*/
从注释可以看出以下几点:
1. PyIntObject实际是long类型;
2. 不可变对象,即创建后不能改变它的值;
3. PyIntObject提供了若干函数;
关于第二点,可以参考如下代码:

所以,看上去是a改变了值,实际上a是引用了不同的整数对象。



注释下面就是PyIntObject的定义了。
typedefstruct{
PyObject_HEAD
longob_ival;
}PyIntObject;
所以展开来的话,主要就包含了引用计数、对象类型和表示值的long ob_ival。

每一种类型有独有的特性和操作,对象的很多信息都放在对应的类型中,比如PyIntObject很多信息放在PyInt_Type中。
PyInt_Type定义在intobject.c中:

PyTypeObjectPyInt_Type= {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"int",
sizeof(PyIntObject),
0,
(destructor)int_dealloc,/* tp_dealloc */
(printfunc)int_print,/* tp_print */
0,/* tp_getattr */
0,/* tp_setattr */
(cmpfunc)int_compare,/* tp_compare */
(reprfunc)int_to_decimal_string,/* tp_repr */
&int_as_number,/* tp_as_number */
0,/* tp_as_sequence */
0,/* tp_as_mapping */
(hashfunc)int_hash,/* tp_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 */
};

所以前面几项宏展开来是:
PyTypeObject PyInt_Type = {
_PyObject_EXTRA_INIT
1, //引用计数
PyType_Type, //对象类型
0, //可变部分中items的数目,PyIntObject为不可变对象
"int", //类型名称
sizeof(PyIntObject), //该类型的基本大小
0, //类型包含的item的大小
......
}
后面的信息就是一些类型拥有的操作,显而易见的有创建对象和删除对象、输出、比较、整数操作和成员函数。
比如int_as_numbers的定义如下:
staticPyNumberMethodsint_as_number= {
(binaryfunc)int_add,/*nb_add*/
(binaryfunc)int_sub,/*nb_subtract*/
(binaryfunc)int_mul,/*nb_multiply*/
(binaryfunc)int_classic_div,/*nb_divide*/
(binaryfunc)int_mod,/*nb_remainder*/
(binaryfunc)int_divmod,/*nb_divmod*/
(ternaryfunc)int_pow,/*nb_power*/
(unaryfunc)int_neg,/*nb_negative*/
(unaryfunc)int_int,/*nb_positive*/
(unaryfunc)int_abs,/*nb_absolute*/
(inquiry)int_nonzero,/*nb_nonzero*/
(unaryfunc)int_invert,/*nb_invert*/
(binaryfunc)int_lshift,/*nb_lshift*/
(binaryfunc)int_rshift,/*nb_rshift*/
(binaryfunc)int_and,/*nb_and*/
(binaryfunc)int_xor,/*nb_xor*/
(binaryfunc)int_or,/*nb_or*/
......
}
这里列出了一些基本运算,如加减乘除,还有位移、逻辑、幂运算等。
考虑一下加法运算过程。
staticPyObject*
int_add(PyIntObject*v,PyIntObject*w)
{
registerlonga,b,x;
CONVERT_TO_LONG(v,a);
CONVERT_TO_LONG(w,b);
/* casts in the line below avoid undefined behaviour on overflow */
x= (long)((unsignedlong)a+b);
if((x^a) >= 0 || (x^b) >= 0)
returnPyInt_FromLong(x);
returnPyLong_Type.tp_as_number->nb_add((PyObject*)v, (PyObject*)w);
}
实际上是long类型的加法运算,并对运算结果进行判断是否溢出。
采取异或运算判断与0的比较结果,是为了判断符号位的变化。
考虑:正数+正数,负数+负数,正数+负数。
第一种情况下溢出,那么结果x将为负数,不满足if判断。
第二种情况下溢出,那么结果x将为正数,不满足if判断。
第三种情况,不会溢出,并且x的符号位必然和其中一个数相同,满足或的if判断。



最后是关于小整数和大整数的管理问题。
Python为小整数建立了内存池,小整数的范围可以自己定义(修改源码重新编译),因为小整数是使用十分频繁的对象。
而对于大整数,Python也采取了一定的措施。

先来看看创建一个整数对象的过程。
参考如下函数:

PyObject*
PyInt_FromLong(longival)
{
registerPyIntObject*v;
#ifNSMALLNEGINTS+NSMALLPOSINTS> 0
if(-NSMALLNEGINTS<=ival&&ival<NSMALLPOSINTS) {
v=small_ints[ival+NSMALLNEGINTS];
Py_INCREF(v);
#ifdefCOUNT_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)
returnNULL;
}
/* Inline PyObject_New */
v=free_list;
free_list= (PyIntObject*)Py_TYPE(v);
PyObject_INIT(v, &PyInt_Type);
v->ob_ival=ival;
return(PyObject*)v;
}

该函数会对传进来的参数判断是否在小整数范围内(-NSMALLNEGINT ~ NSMALLPOSINTS),如果在就直接在small_ints数组里取。
staticPyIntObject*small_ints[NSMALLNEGINTS+NSMALLPOSINTS];
如果不是小整数,那么涉及的就是对大整数的处理。

在对大整数的处理中,首先涉及的是free_list,它被如下初始化:
staticPyIntObject*free_list=NULL;
所以,当第一次遇到大整数的时候,会调用函数fill_free_list()来新建一个链表。

#defineBLOCK_SIZE 1000/* 1K less typical malloc overhead */
#defineBHEAD_SIZE 8/* Enough for a 64-bit pointer */
#defineN_INTOBJECTS ((BLOCK_SIZE-BHEAD_SIZE) /sizeof(PyIntObject))

struct_intblock{
struct_intblock*next;
PyIntObjectobjects[N_INTOBJECTS];
};

typedefstruct_intblockPyIntBlock;

staticPyIntBlock*block_list=NULL;
staticPyIntObject*free_list=NULL;

staticPyIntObject*
fill_free_list(void)
{
PyIntObject*p, *q;
/* Python's object allocator isn't appropriate for large blocks. */
p= (PyIntObject*)PyMem_MALLOC(sizeof(PyIntBlock));
if(p==NULL)
return(PyIntObject*)PyErr_NoMemory();
((PyIntBlock*)p)->next=block_list; //在成功分配内存后,将next指针指向上一个块(第一次为NULL)
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]; //指针p指向数组中第一个元素
q=p+N_INTOBJECTS; //指针q指向数组中最后一个元素的下一个(越界了)
while(--q>p) //利用(滥用)对象的ob_type指针来将所有元素链接在一起
Py_TYPE(q) = (struct_typeobject*)(q-1);
Py_TYPE(q) =NULL; //最后一个(实际是第一个,因为是从最后向前遍历)的ob_type指针指向NULL
returnp+N_INTOBJECTS- 1; //返回数组的最后一个元素的地址
}

注释里面说明了Python的对象分配器不适合多个大内存块,所以一次获取的大小是sizeof(PyIntBlock)。
PyIntBlock里面包含了一个next指针和一个PyIntObject数组。
为了方便,将说明放在代码中进行注释。

接着回到PyInt_FromLong函数

{
......
v=free_list; //v指向数组的最后一个元素,最新未使用的PyIntObject
free_list= (PyIntObject*)Py_TYPE(v); //free_list指向最新未使用的PyIntObject,目前未倒2个数组元素,注意,这里是用ob_type指针来链接的
PyObject_INIT(v, &PyInt_Type); //对v进行初始化,即刚得到的整数对象
v->ob_ival=ival; //设置整数对象的值
return(PyObject*)v; //返回整数对象
}



补充。
intobject.c开头的一段注释值得注意。
/* Integers are quite normal objects, to make object handling uniform.
(Using odd pointers to represent integers would save much space
but require extra checks for this special case throughout the code.)
Since a typical Python program spends much of its time allocating
and deallocating integers, these operations should be very fast.
Therefore we use a dedicated allocation scheme with a much lower
overhead (in space and time) than straight malloc(): a simple
dedicated free list, filled when necessary with memory from malloc().

block_list is a singly-linked list of all PyIntBlocks ever allocated,
linked via their next members. PyIntBlocks are never returned to the
system before shutdown (PyInt_Fini).

free_list is a singly-linked list of available PyIntObjects, linked
via abuse of their ob_type members.
*/
这一段主要是说为了避免过多的内存分配开销,采用了特定的策略来管理整数对象的内存分配。
block_list是一个单向链表,保存着所有分配过的PyIntBlock,通过next指针链接,它会一直存在着,直到系统关闭(PyInt_Fini)。
free_list是PyIntObject的单向链表,通过对象的ob_type成员链接,这是忽略类型安全的“滥用”。
小整数也是通过这两个数据结构来管理的,只不过它是在一开始就初始化好,而大整数是运行时需要才创建的。

下面是大整数创建过程的草图。

分享到:
评论

相关推荐

    Python学习笔记(干货) 中文PDF完整版.pdf

    这份"Python学习笔记"涵盖了从环境搭建到基础语法,再到数据类型和控制结构等关键知识点,旨在为初学者提供全面的学习指导。 首先,1.1章节介绍了Python的基础,包括Python的起源和历史。Python是由Guido van ...

    python核心笔记.pdf

    【Python核心笔记】深入浅出地探讨了Python这一强大且多用途的编程语言。Python以其简单易用且功能强大的特性,赢得了广大开发者的喜爱。它是一种解释型的高级编程语言,支持面向对象编程,同时也具备过程化编程的...

    Python学习笔记.pdf

    #### 二、Python学习笔记概览 **知识点:** 1. **程序的概念与调试:** 包括程序的定义、作用以及如何进行调试,理解程序执行流程中的错误和异常处理。 2. **变量、表达式与语句:** 探讨变量的声明与使用,表达式...

    Python 学习笔记 第二版.pdf

    ### Python学习笔记第二版知识点概览 #### 一、Python语言基础 - **虚拟机**:Python运行在一种称为Python虚拟机(PVM)的环境中。这种虚拟机负责执行Python字节码,提供了语言级别的抽象层,使得Python程序可以在...

    小甲鱼python教程笔记

    小甲鱼 Python 教程笔记 本教程笔记涵盖了 Python 的基础知识点,包括变量、字符串、列表、元组、布尔类型、逻辑运算符、循环结构、列表访问、成员资格运算符、is 运算符、引用和拷贝、列表推导式、元组的使用、...

    千峰python课件笔记+源码 (凯哥)

    千锋python基础教程:1、第一个python程序与数据存储 '千锋python基础教程:2、print&input;与变量和运算符' 千锋python基础教程:3、字符串与循环中的while '千锋python基础教程:4、布尔&list;与条件循环语句与...

    数学建模常用算法(Python 程序及数据)- 整数规划与非线性规划.zip

    例如,06第6章中的"整数规划"部分可能涵盖了定义问题、构建目标函数、设置约束条件以及使用Python中的库(如`Pulp`或`Gurobi`)来求解整数规划问题的方法。 非线性规划则涉及到目标函数或约束条件为非线性的情况。...

    python笔记

    廖雪峰Python笔记总结 廖雪峰Python笔记涵盖了Python语言的基础知识,从最基本的概念到模块部分,不包括函数式编程。下面是对该笔记的知识点总结: Python基础 * Python语言的概述:Python是一种高级的、解释性的...

    《python核心笔记》

    ### Python核心笔记知识点总结 #### 一、Python简介与特性 **定义与理解:** - **定义:** Python是一种支持面向对象的解释型高级编程语言,由Guido van Rossum在1991年首次发布。 - **特性:** - **简单而强大**...

    Python学习笔记第二版

    - **1.2 类型和对象**:解释Python中的数据类型和对象的概念,包括基本类型如整数、浮点数、字符串等,以及复合类型如列表、元组、字典等。 - **1.3 名字空间**:讨论Python中名字空间的作用及其工作机制,包括...

    计算机二级python自学笔记PDF

    接着,笔记可能深入到面向对象编程的概念,讲解类与对象、继承、封装和多态等核心概念,这是Python中实现复杂逻辑和复用代码的关键。 在函数和模块部分,笔记可能会强调函数式编程思想,如高阶函数、闭包、装饰器...

    马哥python课堂笔记-马哥教育PYTHON相关基础笔记.pdf

    在马哥教育的PYTHON相关基础笔记中,我们看到几个关键知识点: 1. **推荐书籍**:学习Python时,有几本经典教材值得参考,包括《Python Cookbook》、《Learn Python the Hard Way》、《Google's Python Class》以及...

    effective python学习笔记.pdf

    记录了我的effective-Python学习笔记,精简了effective-Python中重要的部分。effective-Python是一本值得多看几遍的书,但是看后面的几遍的时候完全可以直接看自己的学习笔记。此学习笔记侧重与比较实用的部分即前四...

    python学习笔记.pdf

    在这份《python学习笔记.pdf》中,记录了Python编程的基础知识和一些技巧,内容涵盖了字符串处理、变量操作、数据结构、循环、条件判断等方面。以下是对学习笔记中提到知识点的详细说明。 ### 字符串处理 在Python...

    python入门笔记(推荐)

    这篇“Python入门笔记”旨在帮助初学者快速掌握Python的基础知识,通过实践操作来加深理解。 首先,Python的语法特点是它的一大亮点。Python代码强调可读性,遵循“缩进决定代码块”的原则,避免了大括号带来的视觉...

    Python学习笔记-王纯业

    5. **面向对象编程**:Python是面向对象的语言,初学者会学习类的定义、对象的创建和方法的使用,包括继承、封装和多态等面向对象的概念。 6. **异常处理**:学习如何使用try/except语句进行错误处理,以及finally...

    python基础笔记html.rar

    6. **面向对象编程**:Python支持面向对象编程,可以定义类(class),创建对象。类包含属性(variables)和方法(functions),是面向对象编程的基础。 7. **标准库**:Python有一个庞大的标准库,包含各种常用的...

    Python编程笔记 Python开发知识总结整理 Python核心笔记 共51页.pdf

    笔记分为两大部分,第一部分是Python的核心概念,第二部分涉及更高级的主题。 在前言中,作者可能介绍了编写此笔记的背景、目的以及对Python语言的基本介绍。关于《Python核心编程》(第二版),这可能是一本被广泛...

    Python学习笔记--皮大庆

    特别地,笔记中还提到了如何在Python中重定义操作符和继承机制的使用,这些都是面向对象编程中的重要概念。重定义操作符可以让用户自定义类型的行为,而继承则可以创建出具有共同特性的新类。 从笔记内容来看,...

Global site tag (gtag.js) - Google Analytics