python结构体 list_深入 Python(15)-创建 List Object

List 对象比 String 对象更简单,主要维护一个 Object * 数组,所以 List 对象的创建也更简单。其代码如下:

// Objects/listobject.c:156PyObject *

PyList_New(Py_ssize_t size)

{

PyListObject *op;

if (size < 0) {

PyErr_BadInternalCall();

return NULL;

}

// 注意这里,free_list 是一个全局数组,保存的是已经不再使用的 List Object。 if (numfree) {

numfree--;

op = free_list[numfree];

_Py_NewReference((PyObject *)op);

} else {

op = PyObject_GC_New(PyListObject, &PyList_Type);

if (op == NULL)

return NULL;

}

if (size <= 0)

op->ob_item = NULL;

else {

op->ob_item = (PyObject **) PyMem_Calloc(size, sizeof(PyObject *));

if (op->ob_item == NULL) {

Py_DECREF(op);

return PyErr_NoMemory();

}

}

Py_SIZE(op) = size;

op->allocated = size;

_PyObject_GC_TRACK(op);

return (PyObject *) op;

}

过程并不复杂,除过一些错误处理代码,首先会尝试从 free_list 中复用闲置的 List Object 对象,如果没有闲置 List Object 对象就不得不申请内存了,所以 List Object 结构体是可回收利用的,关于 free_list 稍晚再看,让我们尽快创建 List Object。List Object 的实际数据区域是其 ob_item 成员,在获得 List Object 结构后,需要通过 PyMem_Calloc 从内存池中分配空间,空间大小由参数 size 指定。最后 4 行代码说明,一个新建的 List Object 的allocated 和 size 是相同的。

free_list 机制

Python 作为一种动态语言,即使是非常基本的数据,也需要一些额外的头部来保存类型信息,这使得 Python 中数据创建的开销比较大,在很多地方 Python 都采用了一些缓存、池方案,进行内存方面的优化,比如 String Object 中的 interned 机制、静态的 latin 字母表等。

free_list 是针对 List Obejct 的优化,Python 准备了一个全局数组,用于回收那些可被 reuse 的 List Object,而不是频繁的销毁、创建 List Object。

// Objects/listobject.c:120/* Empty list reuse scheme to save calls to malloc and free */

#ifndef PyList_MAXFREELIST#define PyList_MAXFREELIST 80#endifstatic PyListObject *free_list[PyList_MAXFREELIST];

static int numfree = 0;

可以看到 free_list 的大小是 80,在 Python 刚启动的时候,这是一个空数组,numfree 为 0。什么时候 free_list 才会被填充呢?一种方法是在 Python 启动之初就预分配 80 个空的 List Object 对象,并将这些指针填充到 free_list 中,Python 选择了另外一种更紧凑的做法,在 List Object 的析构方法(C 语言当然没有“析构”的概念,其实说的是 list_dealloc 函数)中有如下代码:

// Objects/listobject.c:359static void

list_dealloc(PyListObject *op)

{

Py_ssize_t i;

PyObject_GC_UnTrack(op);

Py_TRASHCAN_BEGIN(op, list_dealloc)

if (op->ob_item != NULL) {

// 释放 ob_item 数组,该数组不是 GC 内存。 while (--i >= 0) {

Py_XDECREF(op->ob_item[i]);

}

PyMem_FREE(op->ob_item);

}

// 如果 free_list 还没满,就把当前 List Object 插入 free_list 的结尾。 if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))

free_list[numfree++] = op;

else

Py_TYPE(op)->tp_free((PyObject *)op);

Py_TRASHCAN_END

}

在 List Object 析构中,优先考虑将其放回 free_list 中 reuse,如果 free_list 已经满了才会真正释放 List Object。 当 free_list 中有 2 个可用对象时,free_list 看起来是这样。

此时有一个新的 List Object 被析构,其 ob_item 被释放后,List Object 结构会被追加在 free_list 的尾部。

numfree 实际上标明了 free_list 的最大可用区域。当需要创建 List Object 时,则反之,numfree 减少,free_list 尾部左移一个元素,直到用尽 free_list。

虽然 Python 的性能一直被诟病,不过开发者真的在优化上不遗余力,念在她这么好用,其实已经很不错了!

关注我,了解程序员的烧脑日常,还有开源 Python 教程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您的问题是关于 Boost Python 中如何处理参数为结构体指针的情况,以及如何使用 Boost Python 的原始指针构造函数。 首先,对于结构体指针参数,您可以使用 Boost Python 的 `boost::python::ptr` 类型来传递指针。例如,假设您有一个名为 `MyStruct` 的结构体,您可以在 Python创建一个 `MyStruct` 的实例,并将其传递给 C++ 函数,代码如下: ```c++ #include <boost/python.hpp> struct MyStruct { int x; int y; }; void my_func(boost::python::ptr<MyStruct> ptr) { if (ptr.get()) { std::cout << "x: " << ptr->x << ", y: " << ptr->y << std::endl; } else { std::cout << "ptr is null" << std::endl; } } BOOST_PYTHON_MODULE(my_module) { boost::python::class_<MyStruct>("MyStruct", boost::python::init<>()) .def_readwrite("x", &MyStruct::x) .def_readwrite("y", &MyStruct::y); boost::python::def("my_func", my_func); } ``` 然后在 Python创建一个 `MyStruct` 实例,并将其传递给 `my_func` 函数: ```python import my_module s = my_module.MyStruct() s.x = 10 s.y = 20 my_module.my_func(s) ``` 对于原始指针构造函数,您可以使用 `boost::python::make_constructor` 函数来创建一个构造函数,该构造函数接受一个原始指针作为参数。例如,假设您有一个名为 `MyClass` 的类,它有一个接受 `int` 和 `double` 参数的构造函数,并且您想要创建一个接受 `int*` 和 `double*` 参数的构造函数,代码如下: ```c++ #include <boost/python.hpp> class MyClass { public: MyClass(int x, double y) : x_(x), y_(y) {} private: int x_; double y_; }; MyClass* create_myclass(int* x, double* y) { return new MyClass(*x, *y); } BOOST_PYTHON_MODULE(my_module) { boost::python::class_<MyClass>("MyClass", boost::python::init<int, double>()) .def("__init__", boost::python::make_constructor(&create_myclass)); boost::python::def("create_myclass", &create_myclass, boost::python::return_value_policy<boost::python::manage_new_object>()); } ``` 然后在 Python 中可以使用 `create_myclass` 函数来创建 `MyClass` 实例: ```python import my_module x = 10 y = 20.0 my_obj = my_module.create_myclass(x, y) ``` 需要注意的是,使用原始指针构造函数需要确保手动管理内存,否则可能会导致内存泄漏或者悬挂指针等问题。因此,在上面的例子中,我还使用了 `boost::python::manage_new_object` 策略来确保 Python 自动管理对象的内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值