下面是一個例子(cbk。Ç),即可以作爲這個任務的主鏈:
#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
- 相當於__new__
在的Python) - 初始化它們 - 加入
- 析構函數(
Key_dealloc
- 即不正好相反 - - 在等效__del__
的Python)加入,以及,以避免內存泄漏(這只是以前的子彈後果)
- 訪問
InnerStruct
的x
構件通過Key_getX
,Key_setX
功能(注意,它們在Key_getsets
引用)來完成:
- 從蟒,內
x
構件,將由key_instance.x
被訪問,因爲它是一個Key
實例屬性
- 這樣更有意義比使用的吸氣劑(
get_x()
)和一個設置器(69),更的Python IC
- 然而,如果吸氣劑/調節器的方式是優選的,
Key_getX
,Key_setX
簽名應該略作修改(I想去掉最後一個參數會做),他們應該在Key_methods
被referenceded - 應指定KeyType
爲tp_methods(在上述網頁還介紹)
- 當添加新成員
InnerStruct
,只爲x
完成的東西需要被複制和適應(當然,如果有將是顯得過於相似的功能,代碼需要重構 - 但這是外電流範圍)
- 最後一部分是相當標準的Python擴展模塊代碼
EDIT0:1 ST評論後,好像問題是棘手比它似乎。不知道我是否還是錯了,因爲這看起來不是什麼大不了的事情。改變是(據我所知),inner
指針應該來自別的地方(另一個庫(.dll。)),而不是在構造函數中創建。改變爲例如模仿新(希望預期的)行爲:
- 由於
InnerStruct
指針由外部庫返回(把它稱爲external.dll),該結構定義在頭文件被移動屬於該庫 - 稱之爲external.h(如下圖),這是由cbk.c
- 包括會更有意義庫出口的一些數據通過一個函數(也通過庫輸出):
getExternalPtr
這可能會有爭議 - 目前它只有(虛擬):dummyArg0
- 由於
getExternalPtr
內分配內存,將是有意義的具有解除分配(delExternalPtr
)相應的功能,以避免內存泄漏和未定義的行爲(例如如果內存分配在一個地方,則釋放到另一個地方,並且這兩個地方應該得到不同的運行時間(C runtimes)。通過getExternalPtr
返回的任何指針應該傳給delExternalPtr
恰好一次
- 在2以上的功能現在是從
Key_new
和Key_dealloc
調用。如果這仍然不是OK,並且需要經過創作修改(儘管它可能是一些種族問題會出現)的對象,成員可以像做:((KeyObject*)keyInstancePyObjectPtr)->inner = getExternalPtr(0);
只有一個陷阱:
keyInstancePyObjectPtr
(這是一個通用的PyObject*
)應Key_Type
類型。 Key_CheckExact
宏觀正是這麼做的檢查
現在,模塊依賴(是鏈接於)在外部 LIB(不知道的東西實際上是如何),但可以這麼改到動態( DLL)裝載(經由[man]: DLOPEN(3)/[man]: DLSYM(3)或[MSDN]: LoadLibrary function)/ [MSDN]: GetProcAddress function
外部庫代碼:
external.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
external.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
很難從代碼片段弄清楚。什麼是'x'(來自'myObject.x()') - 它看起來像一個方法。還有什麼是'myStruct * s'?看起來你直到最後沒有閱讀_Python_頁面(是的,它很長)。請發佈完整的代碼,並解釋您的問題。順便說一句:_C_模塊編譯?如果是,是否可以在_Python_中導入? – CristiFati
我確實要實現'x'作爲對象的一種方法,這樣做不是我所遇到的問題。假設結構是 typedef struct {x,y; unsigned char a,r,g,b; } 我寫的對象確實編譯了,我可以在Python中創建這些對象並與之交互。我知道如何爲C中的Python對象執行方法。我遇到的問題是如何將該指針放入KeyObject結構中。一旦我創建了KeyObject,我就無法看到如何獲得這個結構。 –
_Python_不知道指針。您應該能夠從_Python_訪問(r/w)內部結構體字段,但它只是一個數字。我在這裏看到一些過度嵌套(如果我正確的話)。一種方法是直接在'KeyObject'中移動'myStruct'字段。 – CristiFati