故事:我使用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