发布于2020-03-16 22:06 阅读(1452) 评论(0) 点赞(21) 收藏(4)
对象是 python 中最核心的一个概念,在python的世界中,一切都是对象,整数、字符串、甚至类型、整数类型、字符串类型,都是对象。
Python 中凡事皆对象,而其中 PyObject 又是所有对象的基础,它是 Python 对象机制的核心。因为它是基类,而其他对象都是对它的继承。
打开 Include/python.h
中声明如下:
#define PyObject_HEAD \
_PyObject_HEAD_EXTRA \
Py_ssize_t ob_refcnt; \
struct _typeobject *ob_type;
typedef struct _object {
PyObject_HEAD
} PyObject;
PyObject 有两个重要的成员对象:
在python中,预先定义了一些类型对象,比如 int 类型、str 类型、dict 类型等,这些我们称之为内建类型对象,这些类型对象实现了面向对象中"类"的概念。
这些内建对象实例化之后,可以创建类型对象所对应的实例对象,比如 int 对象、str 对象、dict 对象。这些实例对象可以视为面向对象理论中的“对象"这个概念在python中的体现。
#define PyObject_VAR_HEAD \
PyObject_HEAD \
Py_ssize_t ob_size; /* Number of items in variable part */
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
printfunc tp_print;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
cmpfunc tp_compare;
reprfunc tp_repr;
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
/* Attribute descriptor and subclassing stuff */
struct PyMethodDef *tp_methods;
struct PyMemberDef *tp_members;
struct PyGetSetDef *tp_getset;
struct _typeobject *tp_base;
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
Py_ssize_t tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
freefunc tp_free; /* Low-level free-memory routine */
inquiry tp_is_gc; /* For PyObject_IS_GC */
PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */
PyObject *tp_cache;
PyObject *tp_subclasses;
PyObject *tp_weaklist;
destructor tp_del;
...
} PyTypeObject;
这当中,我们需要关注几个重点成员变量:
定长对象比较好理解,例如一个整数对象,无论这个数值多大,它的存储长度是一定的,这个长度由 _typeobject 来指定,不会变化。
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
变长对象在内存中的长度是不一定的,所以需要 ob_size 来记录变长部分的个数,需要注意的是,这个并不是字节的数目。
#define PyObject_VAR_HEAD \
PyObject_HEAD \
Py_ssize_t ob_size; /* Number of items in variable part */
typedef struct {
PyObject_VAR_HEAD;
long ob_shash;
int ob_sstate;
char ob_sval[1];
/* Invariants:
* ob_sval contains space for 'ob_size+1' elements.
* ob_sval[ob_size] == 0.
* ob_shash is the hash of the string or -1 if not computed yet.
* ob_sstate != 0 iff the string object is in stringobject.c's
* 'interned' dictionary; in this case the two references
* from 'interned' to this object are *not counted* in ob_refcnt.
*/
} PyStringObject;
代码如下:
a = int(10)
Python 主要做了以下操作:
我们先看一下 PyInt_Type的代码实现:
PyTypeObject PyInt_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 */
};
这里我们对 int_new 方法进行展开, int_new 方法就是创建函数,类似于 C++ 中的构造函数,用来生成PyIntObject 代码如下:
static PyObject *
int_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *x = NULL;
int base = -909;
static char *kwlist[] = {"x", "base", 0};
if (type != &PyInt_Type)
return int_subtype_new(type, args, kwds); /* Wimp out */
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:int", kwlist,
&x, &base))
return NULL;
if (x == NULL) {
if (base != -909) {
PyErr_SetString(PyExc_TypeError,
"int() missing string argument");
return NULL;
}
return PyInt_FromLong(0L);
}
if (base == -909)
return PyNumber_Int(x);
if (PyString_Check(x)) {
/* Since PyInt_FromString doesn't have a length parameter,
* check here for possible NULs in the string. */
char *string = PyString_AS_STRING(x);
if (strlen(string) != PyString_Size(x)) {
/* create a repr() of the input string,
* just like PyInt_FromString does */
PyObject *srepr;
srepr = PyObject_Repr(x);
if (srepr == NULL)
return NULL;
PyErr_Format(PyExc_ValueError,
"invalid literal for int() with base %d: %s",
base, PyString_AS_STRING(srepr));
Py_DECREF(srepr);
return NULL;
}
return PyInt_FromString(string, NULL, base);
}
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(x))
return PyInt_FromUnicode(PyUnicode_AS_UNICODE(x),
PyUnicode_GET_SIZE(x),
base);
#endif
PyErr_SetString(PyExc_TypeError,
"int() can't convert non-string with explicit base");
return NULL;
}
最后通过 PyInt_FromLong 方法对新产生的对象的type信息就行赋值为 PyInt_Type,并设置整数的具体数值。其中如果是小整数,则可以从 small_ints 数组中直接放回。
#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject))
#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */
#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
struct _intblock {
struct _intblock *next;
PyIntObject objects[N_INTOBJECTS];
};
typedef struct _intblock PyIntBlock;
static PyIntBlock *block_list = NULL;
static PyIntObject *free_list = NULL;
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);
(void)PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
return (PyObject *) v;
}
为了性能考虑,python 中对小整数有专门的缓存池,这样就不需要每次使用小整数对象时去用 malloc 分配内存以及free释放内存。
小整数之外的大整数怎么避免重复分配和回收内存呢?
Python 的方案是 PyIntBlock。PyIntBlock 这个结构就是一块内存,里面保存 PyIntObject 对象。一个 PyIntBlock 默认存放 N_INTOBJECTS 对象。
PyIntBlock 链表通过 block_list 维护,每个block中都维护一个 PyIntObject 数组 objects,block 的 objects 可能会有些内存空闲,因此需要另外用一个 free_list 链表串起来这些空闲的项以方便再次使用。objects 数组中的 PyIntObject 对象通过 ob_type 字段从后往前链接。
小整数的缓存池最终实现也是生存在 block_list 维护的内存上,在 python 初始化时,会调用 PyInt_Init 函数申请内存并创建小整数对象。
原文来自兔子先生网站:https://www.xtuz.net/detail-134.html
查看原文 >>> Python源码剖析 - 对象初探
如果你对Python语言感兴趣,可以关注我,或者关注我的微信公众号:xtuz666
原文链接:https://www.cnblogs.com/xtuz/p/12454730.html
作者:坚持就是胜利
链接:https://www.pythonheidong.com/blog/article/262423/89c9a6418f9dac0e1d64/
来源:python黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!