故事:我使用ctypes從python通信到C和其他方式。我也在製作我正在嘗試連接的C共享庫。在這個開發階段,它只是一個簡單的庫,在深入代碼之前測試所有的概念。它是用C++編寫的,用extern「C」暴露函數,沒什麼特別。我用原始參數/返回類型,指針和函數回調來測試函數。ctypes和構建元類:類型錯誤:*類*實例,而不是LP_ *類*實例
現在我想通過結構。由於我是一個懶惰的程序員,我打算將C++結構傳遞給一個統一的C表示形式(即簡單字典和列表的組合)並將其處理爲python,然後將其轉換爲真正的python對象(即.a python字典和列表的組合)。
問題:爲了達到這個目的,我首先在C++中定義了一個模板化字典,其實現僅僅用於測試一個鍵值對的鏈表,其中字典擁有根。然後,對於需要專門化的每個函數,將該專業化的typedef用作C結構體。
的代碼看起來是這樣的(而不是實際的代碼):
#include <cstdlib>
template <typename key_t, typename value_t>
struct DictNode
{
key_t key;
value_t value;
};
template <typename key_t, typename value_t>
struct Dict
{
typedef DictNode<key_t, value_t> node_t;
node_t root;
};
typedef Dict<int, char> Dict_int_char;
extern "C" Dict_int_char* example_new()
{
Dict_int_char* result;
result = (Dict_int_char*)malloc(sizeof(Dict_int_char));
return result;
}
extern "C" void example_delete(Dict_int_char* value)
{
free(value);
}
現在,蟒蛇,以避免產生一類爲每一個專業化的,我下面的相同的方法。一個方法將爲我創建給定鍵值類型的專用類。
的代碼看起來是這樣的(實際的代碼):
import types
import ctypes
# This is to provide some hiding of the module internals
# Suggestions on a more pythonic way are gladly accepted
class __Internals:
"""
Creates class to interface with a C structure comming from a
typedef'd C++ class template specialization. This method recieves
the types of the template class, creates the ctypes classes to
interface with the specialized class (which has been typedef'd)
and returns them for usage with ctypes.
"""
@staticmethod
def __DictClassCreate__(key_t, value_t):
# Foward declare the classes
class InterfaceListNode(ctypes.Structure):
pass;
class InterfaceList(ctypes.Structure):
pass;
#### NODE
# Node class
nodeType = InterfaceListNode;
# The pointer-to-node class
nodeTypePointerType = ctypes.POINTER(nodeType);
# Fields of the node class (next, key, value)
nodeType._fields_ = [("next", nodeTypePointerType),
("key", key_t),
("value", value_t) ];
# Function to create a node pointer
def nodeTypePointerCreate(cls, value=None):
if(value is None):
return nodeTypePointerType();
else:
return nodeTypePointerType(value);
# Bind the function to the node class
nodeType.pointer = types.MethodType(nodeTypePointerCreate, nodeType);
#### DICT
# Dict class
dictType = InterfaceList;
# The pointer-to-dict class
dictTypePointerType = ctypes.POINTER(dictType);
# Useful for dict to know the types of it's nodes
dictType._nodeType = nodeType;
# Fields of the dict class (root)
dictType._fields_ = [("root", ctypes.POINTER(nodeType))];
# Function to create a dict pointer
def dictTypePointerCreate(cls, value=None):
if(value is None):
return dictTypePointerType();
else:
return dictTypePointerType(value);
# Bind the function to the dict class
dictType.pointer = types.MethodType(dictTypePointerCreate, dictType);
# For debugging
print 'Inside metaclass generator'
print hex(id(nodeType));
print hex(id(dictType));
# Return just the dict class since it knows about it's node class.
return dictType;
# Create a new specialized dict<c_uint, c_char>
dictType_1 = __Internals.__DictClassCreate__(ctypes.c_uint, ctypes.c_char);
# Obtain the node type of this dict
nodeType_1 = dictType_1._nodeType;
# For debugging
print 'In Script'
print hex(id(nodeType_1));
print hex(id(dictType_1));
# Try to instance this dictionary with 1 element
#(not NULL root, NULL root.next)
dict_1 = dictType_1(nodeType_1(nodeType_1.pointer(), 0, 'a'));
運行此代碼時,將顯示以下輸出:
python SciCamAPI.py
Inside metaclass generator
0x249c1d8L
0x249c588L
In Script
0x249c1d8L
0x249c588L
Traceback (most recent call last):
File "SciCamAPI.py", line 107, in <module>
dict_1 = dictType_1(nodeType_1(nodeType_1.pointer(), 0, 'a'));
TypeError: incompatible types, InterfaceListNode instance instead of LP_InterfaceListNode instance
從打印輸出我可以看見我使用相同的元類來實例化簡單字典,並且它的節點與方法中生成的節點一樣。
我已經在搜索錯誤中附加了LP_,但搜索LP_ python只返回線性問題求解器和this answer。從理解的答案ctypes是從nodeType_1.pointer()(最後一行)創建一個C風格的指針,但那是當node.next被聲明爲[(「next」,nodeTypePointerType) ,...](在nodeType中,字段 = ...)。所以我很迷路。
'dictType_1.root'是一個'LP_InterfaceListNode'字段,即'POINTER(InterfaceListNode)',但是你用一個'InterfaceListNode'而不是一個指針來初始化它。 「LP」是指在分段架構的那一天(在段內)和遠/長指針之後的「長指針」。 Windows類型保留此前綴,即使它不再有意義,例如'LPVOID'和'LPWSTR'。 ctypes最初是一個僅限Windows的軟件包。 – eryksun
謝謝,就是這樣!將最後一行替換爲:'rootNode = nodeType_1(nodeType_1。指針(),0,'a'); dict_1 = dictType_1(nodeType_1.pointer(rootNode));',這樣做。你應該發佈一個接受它的接受者,或者我引用你的話嗎? – jabozzo