2016-02-24 124 views
1

故事:我使用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中,字段 = ...)。所以我很迷路。

+0

'dictType_1.root'是一个'LP_InterfaceListNode'字段,即'POINTER(InterfaceListNode)',但是你用一个'InterfaceListNode'而不是一个指针来初始化它。 “LP”是指在分段架构的那一天(在段内)和远/长指针之后的“长指针”。 Windows类型保留此前缀,即使它不再有意义,例如'LPVOID'和'LPWSTR'。 ctypes最初是一个仅限Windows的软件包。 – eryksun

+0

谢谢,就是这样!将最后一行替换为:'rootNode = nodeType_1(nodeType_1。指针(),0,'a'); dict_1 = dictType_1(nodeType_1.pointer(rootNode));',这样做。你应该发布一个接受它的接受者,或者我引用你的话吗? – jabozzo

回答

0

援引eryksun的评论:

dictType_1.root is an LP_InterfaceListNode field, i.e. POINTER(InterfaceListNode) , but you're initializing it with an InterfaceListNode instead of a pointer to one. "LP" is for "long pointer" from back in the day of segmented architectures that had near (within segment) and far/long pointers. Windows types retain this prefix even though it's no longer meaningful, such as LPVOID and LPWSTR . ctypes was initially a Windows-only package

所以我错过了dictType_1.root转换为指针。将最后一行更改为:

rootNode = nodeType_1(nodeType_1.pointer(), 0, 'a'); 
dict_1 = dictType_1(nodeType_1.pointer(rootNode)); 

解决问题。

相关问题