gpt4 book ai didi

python - 如何在自定义嵌入式Python对象中存储指针

转载 作者:太空宇宙 更新时间:2023-11-04 00:00:33 25 4
gpt4 key购买 nike

我已经按照教程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 */
};

最佳答案

下面是一个示例(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),这足以表明一点
一切都只依赖于 [Python]: Defining New Types页面(问题中也提到了这一点)
由于包装器对象( Key)包含指针( inner),为了避免每次访问指针时都检查它们是否 NULL
添加了一个构造函数( Key_new-相当于Python中的 __new__)-初始化它们
为了避免内存泄漏,还添加了一个析构函数(Python中的等效析构函数),其作用正好相反
访问 Key_dealloc__del__成员是通过 InnerStructx函数完成的(注意,它们在 Key_getX中被引用):
从Python中,内部的 Key_setX成员将由 Key_getsets访问,因为它是一个 x实例属性
这种方法比使用getter( key_instance.x)和setter( Key)更有意义,而且更像蟒蛇
但是,如果首选getter/setter方式,则应稍微修改 get_x()set_x(value)签名(我认为删除最后一个参数就可以了),并应在 Key_getX中引用它们,该签名应指定为 Key_setX作为tp_方法(也在上面的网页中描述)
Key_methods添加新成员时,只需要复制和调整为 KeyType所做的工作(当然,如果有些函数看起来太相似,则应重构代码-但这超出了当前范围)
最后一部分是标准的Python扩展模块代码
伊迪丝0:在第一次评论之后,这个问题似乎比看起来更棘手我不确定我是否还是弄错了,因为这看起来没什么大不了的根据我的理解, InnerStruct指针应该来自其他地方(另一个库(.dll)),而不是在构造函数中创建改为示例以模拟新的(希望是预期的)行为:
由于外部库(称为external.dll)返回一个 x指针,因此结构定义被移动到属于该库的头文件中,称为external.h(如下),该头文件由cbk.c包含
有意义的是,库通过函数(也由库导出): inner导出某些数据,该函数可能带有参数-当前它只有(一个伪)参数: InnerStruct
因为 getExternalPtr在内部分配内存,所以有一个相应的函数来释放内存( dummyArg0)是有意义的,这样可以避免内存泄漏和未定义的行为(例如,如果内存在一个地方分配,在另一个地方释放,这两个地方应该由不同的C运行时分配) getExternalPtr返回的任何指针都应准确地传递给 delExternalPtr一次
以上两个函数现在将从 getExternalPtrdelExternalPtr调用如果这仍然不正常,并且在创建后需要修改对象(尽管可能会出现一些种族问题),则只需一个catch,就可以像这样设置成员: Key_new
Key_dealloc(这是一个通用的 ((KeyObject*)keyInstancePyObjectPtr)->inner = getExternalPtr(0);)应该是 keyInstancePyObjectPtr类型 PyObject*宏正是这样做的
现在,模块依赖于(链接到)外部lib(不确定实际情况如何),但可以将其更改为动态SO(DLL)加载(通过 [man]: DLOPEN(3)/ [man]: DLSYM(3)[MSDN]: LoadLibrary function)/ [MSDN]: GetProcAddress function
外部库代码:
外部.h:
#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

外部c:
#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);
}

测试程序(ckb_Test.py):
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"

输出:
c:\Work\Dev\StackOverflow\q46833364>set PATH=%PATH%;.\external\Win32-Release

c:\Work\Dev\StackOverflow\q46833364>set PYTHONPATH=%PYTHONPATH%;.\ckb\Win32-Release

c:\Work\Dev\StackOverflow\q46833364\>"c:\Install\x86\HPE\OPSWpython\2.7.10__00\python.exe" ckb_test.py

Module: <module 'ckb' from 'c:\Work\Dev\StackOverflow\q46833364\ckb\Win32-Release\ckb.pyd'>
Dir: ['Key', '__doc__', '__file__', '__name__', '__package__']

Class: <type 'ckb.Key'>
Dir: ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'x']

Instance: <ckb.Key object at 0x027A7050>
Dir: ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'x']

Key.x (initial): 1618
Key.x (modified): 123
Traceback (most recent call last):
File "..\ckb_test.py", line 20, in <module>
key.x = 1.0
TypeError: 'x' value must be an int

End

关于python - 如何在自定义嵌入式Python对象中存储指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46833364/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com