关键词:python3,c,拓展
转载自:https://docs.python.org/zh-cn/3.6/extending/newtypes_tutorial.html
系列链接:
1. 环境
- python3.6
- gcc7.5
2. code
#include <Python.h>
#include "structmember.h"
// 定义一个新的object
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
// 清除变量与内存,没有显示的调用
static void
Custom_dealloc(CustomObject *self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free((PyObject *) self);
}
// 对应python中 __new__ 创建对象,没有显示调用
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = PyUnicode_FromString("");
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = PyUnicode_FromString("");
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 123;
}
return (PyObject *) self;
}
// 对应到 python 中 __init__ 初始化对象,没有在程序中显示的调用
static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
if (last) {
tmp = self->last;
Py_INCREF(last);
self->last = last;
Py_XDECREF(tmp);
}
return 0; // 返回0/1
}
// 定义对象的一些属性
static PyMemberDef Custom_members[] = {
{"first", T_OBJECT_EX, offsetof(CustomObject, first), 0,
"first name"},
{"last", T_OBJECT_EX, offsetof(CustomObject, last), 0,
"last name"},
{"number", T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
// 定义模块的函数, 在python中采用module.name()进行调用
static PyObject *
Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
{
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self->last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last");
return NULL;
}
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
// 声明的结构体
static PyMethodDef Custom_methods[] = {
{"name", (PyCFunction) Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
// 定义类类型
static PyTypeObject CustomType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom2.Custom",
.tp_doc = "Custom objects",
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_new = Custom_new,
.tp_init = (initproc) Custom_init,
.tp_dealloc = (destructor) Custom_dealloc,
.tp_members = Custom_members,
.tp_methods = Custom_methods,
};
// 定义一个新module 用的结构体
static PyModuleDef custommodule = {
PyModuleDef_HEAD_INIT,
.m_name = "custom2",
.m_doc = "Example module that creates an extension type.",
.m_size = -1,
};
PyMODINIT_FUNC
PyInit_custom2(void)
{
PyObject *m;
if (PyType_Ready(&CustomType) < 0) // 完善 CustomType 的 tp_alloc
return NULL;
m = PyModule_Create(&custommodule);
if (m == NULL)
return NULL;
Py_INCREF(&CustomType);
PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
return m;
}
/*
1. compile
gcc -shared -fPIC -I/usr/include/python3.6 custom2.c -o custom2.so
- custom2.so,名字需要和模块的名字一致
*/
具体解释,请看代码中的注释
3. python 测试
code
import custom2
# 问题:
# 1. 什么时候调用new方法
# 2. 什么时候调用init方法
# 3. new和init的关系
class my(custom2.Custom):
def __new__(cls, *args, **kwargs):
print("__new__", cls, args, kwargs)
instance = super().__new__(cls, args, kwargs) # 调用父类的__new__方法,就会调用Custom2.c中new方法
print("values:", instance.first, instance.last, instance.number)
return instance
def __init__(self, *args, **kwargs):
print("__init__", self, args, kwargs)
super(my, self).__init__(*args, **kwargs) # 调用父类的__init__方法,就是调用custom2.c中的init方法
print("self.values:", self.first, self.last, self.number)
b = my("boy", "girl")
print(b.name())
c = my(first="boy", last="girl")
print(c.name())
输出:
__new__ <class '__main__.my'> ('boy', 'girl') {}
values: 123
__init__ <__main__.my object at 0x7f97da34ad18> ('boy', 'girl') {}
self.values: boy girl 123
boy girl
__new__ <class '__main__.my'> () {'first': 'boy', 'last': 'girl'}
values: 123
__init__ <__main__.my object at 0x7f97da34ae08> () {'first': 'boy', 'last': 'girl'}
self.values: boy girl 123
boy girl
4. other
- new__和__init 的关系:http://c.biancheng.net/view/5484.html
- CustomObject 和 CustomType 是如何对应起来的呢?
在初始化的时候,有
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
这里是先申请内存type->tp_alloc(type, 0)
,再强制转换成(CustomObject *)
,而申请内存的时候,只需要知道内存的大小,所以type->tp_alloc(type, 0)
相当于new(type->tp_basicsize )
,而tp_basicsize = sizeof(CustomObject)