py3源码[3]-其它数值类型
除了PyIntObject(2.x)和PyLongObject之外,还有如下几种数值类型:
一,bool
//boolobject.c //True和False都是对PyLongObject的一个封装 struct _longobject _Py_FalseStruct = { PyVarObject_HEAD_INIT(&PyBool_Type, 0) //ob_size=0 { 0 } //ob_digit=0 }; struct _longobject _Py_TrueStruct = { PyVarObject_HEAD_INIT(&PyBool_Type, 1) //ob_size=1 { 1 } };
tips:
1,bool的tp_base是PyLong_Type,所以可以:
>>> a=[1,2,3]
>>> a[True]
2
>>> 1==True
True
>>> 0==False
True
2,判断object是否为True,”所有零值或内容长度为零的对象都被视为False”。
//object.c int PyObject_IsTrue(PyObject *v) { Py_ssize_t res; if (v == Py_True) return 1; if (v == Py_False) return 0; if (v == Py_None) return 0; else if (v->ob_type->tp_as_number != NULL && v->ob_type->tp_as_number->nb_bool != NULL) res = (*v->ob_type->tp_as_number->nb_bool)(v); else if (v->ob_type->tp_as_mapping != NULL && v->ob_type->tp_as_mapping->mp_length != NULL) res = (*v->ob_type->tp_as_mapping->mp_length)(v); else if (v->ob_type->tp_as_sequence != NULL && v->ob_type->tp_as_sequence->sq_length != NULL) res = (*v->ob_type->tp_as_sequence->sq_length)(v); else return 1; /* if it is negative, it should be either -1 or -2 */ return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int); }
二,float
//floatobject.h typedef struct { PyObject_HEAD //定长对象 double ob_fval; //内部使用c double类型包装 } PyFloatObject;
tips:
1,也使用了free_list,不过区别于2.x中的PyIntObject,free_list有最长长度限制
#ifndef PyFloat_MAXFREELIST #define PyFloat_MAXFREELIST 100 #endif static int numfree = 0; static PyFloatObject *free_list = NULL; PyObject * PyFloat_FromDouble(double fval) { register PyFloatObject *op = free_list; if (op != NULL) { //free_list中有空间,直接用 free_list = (PyFloatObject *) Py_TYPE(op); numfree--; } else { //否则,malloc出来即可 op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject)); if (!op) return PyErr_NoMemory(); } /* Inline PyObject_New */ PyObject_INIT(op, &PyFloat_Type); op->ob_fval = fval; return (PyObject *) op; } static void float_dealloc(PyFloatObject *op) { if (PyFloat_CheckExact(op)) { if (numfree >= PyFloat_MAXFREELIST) { // 超出最大长度就直接free掉 PyObject_FREE(op); return; } numfree++; Py_TYPE(op) = (struct _typeobject *)free_list; free_list = op; } else Py_TYPE(op)->tp_free((PyObject *)op); }
三,复数
//complexobjec.h typedef struct { double real; double imag; } Py_complex;
>>> a=complex(1.2,1.5)
>>> a
(1.2+1.5j)
四,分数
lib实现:import fractions。
不赘述,请参考:http://woodpecker.org.cn/diveintopython3/native-datatypes.html
参考:
1,雨痕-深入Python编程-RC0.3.pdf
2,http://woodpecker.org.cn/diveintopython3/
py3源码[2]-整数
根据PEP 0237,Py3中已经没有int类型了,py3中的整数对象指的只有PyLongObject了(关于Py2.x中的PyIntObject,《Python源码剖析》介绍的很详细了)。
整数的相关操作都在long_as_number操作集中。
先回答上篇文章遗留的2个问题:
1,PyLongObject的digit ob_digit[1]的作用?
A:是一个常量数组头(PyLongObject是不可变对象,不用考虑多态增长),对象初始化时分配所需要的实际空间并确定数据长度保存在PyObject_VAR_HEAD的ob_size中(tips:每个ob_digit只用了15位表示数字,ob_size的正负表示PyLongObject的正负)。
分析详解
2,long类型如何实现任意大整数的运算?
“PyLongObject是不可变对象,不用考虑多态增长,对象初始化时分配所需要的实际空间并确定数据长度保存在PyObject_VAR_HEAD的ob_size中”。示例:
加法的很简单
//longobject.c /* Add the absolute values of two long integers. */ //低位开始诸位相加 static PyLongObject * x_add(PyLongObject *a, PyLongObject *b) { Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b)); PyLongObject *z; Py_ssize_t i; digit carry = 0; /* Ensure a is the larger of the two: */ if (size_a < size_b) { { PyLongObject *temp = a; a = b; b = temp; } { Py_ssize_t size_temp = size_a; size_a = size_b; size_b = size_temp; } } z = _PyLong_New(size_a+1); if (z == NULL) return NULL; for (i = 0; i < size_b; ++i) { carry += a->ob_digit[i] + b->ob_digit[i]; z->ob_digit[i] = carry & PyLong_MASK; carry >>= PyLong_SHIFT; } for (; i < size_a; ++i) { carry += a->ob_digit[i]; z->ob_digit[i] = carry & PyLong_MASK; carry >>= PyLong_SHIFT; } z->ob_digit[i] = carry; return long_normalize(z); }
乘法则复杂很多,Karatsuba算法(O(n^2)=>O(n^1.58))。
分析详解
依然使用了类似PyIntObject实现中的小整数对象池
//longobject.c #ifndef NSMALLPOSINTS #define NSMALLPOSINTS 257 #endif #ifndef NSMALLNEGINTS #define NSMALLNEGINTS 5 #endif /* Small integers are preallocated in this array so that they can be shared. The integers that are preallocated are those in the range -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). */ static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
tips:
1,int _PyLong_Init(void)
初始化了这个小整数对象池
2,PyObject * PyLong_FromLong(long ival)
展示了如何从c的long类型建立一个PyLong(小整数使用池,其他整数直接malloc)。
问题:
1,《Python源码剖析》提到的整数对象池block_list应该已经不存在了(因为PyLongObject为变长对象)。
既然没有池了,malloc/free会带来的不小性能损耗,这也许是py3性能损耗的一个方面:”Py3.0运行 pystone benchmark的速度比Py2.5慢30%。Guido认为Py3.0有极大的优化空间,在字符串和整形操作上可以取得很好的优化结果。”
另外:底层还有arena这层内存管理机制。
2,long_normalize是否会导致内存泄漏?
/* Normalize (remove leading zeros from) a long int object. Doesn't attempt to free the storage--in most cases, due to the nature of the algorithms used, this could save at most be one word anyway. */ static PyLongObject * long_normalize(register PyLongObject *v)
参考:
1,python内部细节实现好文:www.endless-loops.com/tag/python
py3源码[0]-前言声明
ver Python-3.3.0
http://www.python.org/download/releases/3.3.0/
基本是结合《Python源码剖析》(http://book.douban.com/subject/3117898/)来写的,加上了自己发散扩展的一些内容。
人生很长,专心做一点喜欢的事情吧。
py3源码[1]-object基础
几个重要的struct
//1,基础对象(头) typedef struct _object { _PyObject_HEAD_EXTRA //only for trace Py_ssize_t ob_refcnt; //引用计数 struct _typeobject *ob_type; //指向类型对象(PyTypeObject),它们都是全局变量,例子see 5 } PyObject; //2,变长对象(头) typedef struct { PyObject ob_base; Py_ssize_t ob_size; //抽象元素数目,非字节 } PyVarObject; //3,类型举例:long typedef struct _longobject PyLongObject; struct _longobject { PyObject_VAR_HEAD //PyVarObject digit ob_digit[1]; //? }; //4,类型举例:dict typedef struct { PyObject_HEAD //PyObject Py_ssize_t ma_used; PyDictKeysObject *ma_keys; PyObject **ma_values; } PyDictObject; //5,long类型对象(PyTypeObject) //longobject.c //各个内部类型实际上都是对象,类型对象的类型则是PyType_Type PyTypeObject PyLong_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) //对应到PyVarObject头的3个字段 "int", /* tp_name */ offsetof(PyLongObject, ob_digit), /* tp_basicsize */ sizeof(digit), /* tp_itemsize */ long_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ long_to_decimal_string, /* tp_repr */ &long_as_number, /* tp_as_number */ //数值操作函数集 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ (hashfunc)long_hash, /* tp_hash */ 0, /* tp_call */ long_to_decimal_string, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */ long_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ long_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ long_methods, /* tp_methods */ 0, /* tp_members */ long_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 */ long_new, /* tp_new */ PyObject_Del, /* tp_free */ };
tips:
1,py2 long/int => py3 int
PEP 0237: Essentially, long renamed to int. That is, there is only one built-in integral type, named int; but it behaves mostly like the old long type.
2,关于Py_LIMITED_API
避免extension使用不稳定的py api。
http://docs.python.org/release/3.2.3/whatsnew/3.2.html#pep-384-defining-a-stable-abi
3,PyObject*
泛型指针,可以指向任何一个Py对象,通过ob_type字段实现了多态。
问题:
1,PyLong_Type的tp_base为0,没有继承PyObject?
A:yes,不过是可以通过PyObject*引用的。
2,PyLongObject的digit ob_digit[1]的作用?
3,long类型如何实现任意大整数的运算?
A:这2个问题答案在下一篇文章中给出吧。
leave a comment