我已根据教程https://docs.python.org/2.7/extending/newtypes.html#the-basics在C中创建了一个自定义Python类型。在我的C中,我收到一个指向结构的指针,我希望能够从Python中获取并设置结构中的值,而无需复制它。即。
a = myObject.x() # gets the x value in the struct.
或
myObject.x(255) # sets the x value in the struct.
但是我看不到如何将指针存储在python对象中。
我当前的对象定义目前只是python网站的基本对象实现。
typedef struct {
PyObject_HEAD
myStruct *s;
} KeyObject;
static PyTypeObject KeyType = {
PyVarObject_HEAD_INIT(NULL, 0)
"ckb.Key", /* tp_name */
sizeof(KeyObject), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Key objects", /* tp_doc */
};
static PyMethodDef key_methods[] = {
{NULL} /* Sentinel */
};
答案 0 :(得分:0)
以下是一个示例( cbk.c ),它可以作为此任务的主干:
#include "external.h"
#include "Python.h"
#define MOD_NAME "ckb"
#define KEY_CLASS_NAME "Key"
/*
typedef struct InnerStruct_tag {
int x;
} InnerStruct;
//*/
typedef struct KeyObject_tag {
PyObject_HEAD
InnerStruct *inner;
} KeyObject;
static PyObject *Key_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
KeyObject *self;
self = (KeyObject*)type->tp_alloc(type, 0);
if (self != NULL) {
//self->inner = (InnerStruct*)calloc(1, sizeof(Key));
self->inner = getExternalPtr(1234); // Don't allocate here, get the pointer from external lib
if (self->inner == NULL) {
Py_DECREF(self);
return NULL;
}
}
return (PyObject*)self;
}
static void Key_dealloc(KeyObject *self) {
//free(self->inner);
delExternalPtr(self->inner); // Use the external dellocation function (optional)
Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject *Key_getX(KeyObject *self, void *closure) {
return PyInt_FromLong(self->inner->x);
}
static int Key_setX(KeyObject *self, PyObject *value, void *closure) {
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete 'x'");
return -1;
}
if (!PyInt_Check(value)) {
PyErr_SetString(PyExc_TypeError, "'x' value must be an int");
return -1;
}
self->inner->x = ((PyIntObject*)value)->ob_ival;
return 0;
}
static PyGetSetDef Key_getsets[] = {
{"x", (getter)Key_getX, (setter)Key_setX, "x", NULL},
{NULL} // Sentinel
};
static PyTypeObject Key_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
MOD_NAME"."KEY_CLASS_NAME, /* tp_name */
sizeof(KeyObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)Key_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /* tp_flags */
KEY_CLASS_NAME" objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
Key_getsets, /* 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 */
Key_new, /* tp_new */
};
#define Key_CheckExact(op) ((op)->ob_type == &Key_Type)
static PyMethodDef module_methods[] = {
{NULL} // Sentinel
};
PyMODINIT_FUNC initckb(void) {
PyObject* m;
if (PyType_Ready(&Key_Type) < 0)
return;
m = Py_InitModule3(MOD_NAME, module_methods,
MOD_NAME": Example module that creates an extension type ("KEY_CLASS_NAME").");
Py_INCREF(&Key_Type);
PyModule_AddObject(m, KEY_CLASS_NAME, (PyObject*)&Key_Type);
}
备注强>:
x
),足以成为一个点Key
)包含指针(inner
),因此为了避免每次访问时都检查NULL
:
Key_new
- 相当于 Python中的__new__
) - 初始化它们 - Key_dealloc
- Python 中的等效__del__
- 完全相反 - 也被添加,以避免内存泄漏(这只是以前的子弹后果)InnerStruct
x
成员访问权限是通过Key_getX
,Key_setX
函数完成的(请注意Key_getsets
中引用它们):
x
成员将由key_instance.x
访问,因为它是Key
实例属性
get_x()
)和setter(set_x(value)
)更有意义,而且更多是 Python ic Key_getX
,Key_setX
签名应略微修改(我认为删除最后一个参数会这样做),并且应该在{{1}中引用它们} - 应该将Key_methods
指定为 tp_methods (也在上面的网页中描述)KeyType
添加新成员时,只需要复制和调整InnerStruct
所需的内容(当然,如果有类似的函数,代码应该重构 - 但是这样超出当前范围) EDIT0 :在1 st 评论之后,似乎问题比看起来更棘手。不确定我是否仍然弄错了,因为它似乎没什么大不了的。 (据我所知),更改是x
指针应来自其他位置(另一个库( .dll )),而不是在构造函数中创建。更改为示例以模仿新的(并且希望预期的)行为:
inner
指针,因此结构定义在属于该库的头文件中移动 - 称为 external.h (下),包含在 cbk.c InnerStruct
可能需要参数 - 目前它只有(虚拟)一个:getExternalPtr
dummyArg0
内部分配内存,因此有一个相应的函数可以解除分配它(getExternalPtr
),以避免内存泄漏和未定义的行为(例如如果在一个地方分配了内存,在另一个地方分配了内存,并且这两个地方是由不同的 C 运行时分配的。 delExternalPtr
返回的任何指针都应该传递给getExternalPtr
一次 delExternalPtr
和Key_new
调用上述2个函数。如果这仍然不是 OK ,并且在创建后需要修改对象(虽然可能会出现一些种族问题),可以设置成员喜欢:Key_dealloc
只有一次捕获:
((KeyObject*)keyInstancePyObjectPtr)->inner = getExternalPtr(0);
(通用keyInstancePyObjectPtr
)应为PyObject*
类型。 Key_Type
宏完全检查现在,模块依赖于链接到外部 lib(不确定实际情况如何),但可以更改为< em>动态SO(DLL)加载(通过[man]: DLOPEN(3) / [man]: DLSYM(3)或[MSDN]: LoadLibrary function)/ [MSDN]: GetProcAddress function
外部库代码:
external.h :
Key_CheckExact
external.c :
#if defined (WIN32)
# if defined (EXTERNAL_DYNAMIC)
# if defined EXTERNAL_EXPORTS
# define EXTERNAL_EXPORT __declspec(dllexport)
# else
# define EXTERNAL_EXPORT __declspec(dllimport)
# endif
# else
# define EXTERNAL_EXPORT
# endif
#else
# define EXTERNAL_EXPORT
#endif
typedef struct InnerStruct_tag {
int x;
} InnerStruct;
#if defined (__cplusplus)
extern "C" {
#endif
EXTERNAL_EXPORT InnerStruct *getExternalPtr(int dummyArg0);
EXTERNAL_EXPORT void delExternalPtr(InnerStruct *ptr);
#if defined (__cplusplus)
}
#endif
测试程序( ckb_test.py ):
#include "external.h"
#include <stdlib.h>
InnerStruct *getExternalPtr(int dummyArg0) {
InnerStruct *ret = (InnerStruct*)malloc(sizeof(InnerStruct));
if (ret != NULL)
ret->x = 1618;
return ret;
}
void delExternalPtr(InnerStruct *ptr) {
free(ptr);
}
<强>输出强>:
import traceback import ckb print "\nModule:", ckb print "Dir:", dir(ckb) print "\nClass:", ckb.Key print "Dir:", dir(ckb.Key) key = ckb.Key() print "\nInstance:", key print "Dir:", dir(key) print "\nKey.x (initial):", key.x key.x = 123 print "Key.x (modified):", key.x try: key.x = 1.0 except: traceback.print_exc() del(key) print "\nEnd"