ctypes和构建元类:TypeError:* class * instance而不是LP_ * class * instance

时间:2016-02-24 02:47:21

标签: python c ctypes typeerror metaclass

故事:我使用ctypes从python到C进行通信,反之亦然。我也在制作C共享库我也试图接口。在这个开发步骤中,它只是一个简单的库,可以在深入研究代码之前测试所有概念。它是用C ++编写的库,用extern" C"来展示函数,没什么特别的。我已经使用原始参数/返回类型,指针和函数回调测试了函数。

现在我想传递结构。由于我是懒惰的程序员,我计划将C ++结构传递给统一的C表示(即简单字典和列表的组合)并将其处理为python,这将把它转换为真正的python对象(即。字典和列表的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);
}

现在,在python中,为了避免为每个专业化创建一个类,我遵循相同的方法。一个方法将为我创建给定键值类型的专门类。

代码看起来像这样(实际代码):

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

从打印输出中我可以看到我使用相同的元类来实现简单的dict,并将它的节点作为方法中生成的节点。

我已经用Google搜索了错误中附加的LP_,但搜索LP_ python只返回线性问题解算器和this answer。根据对答案的理解,ctypes正在从nodeType_1.pointer()(最后一行)创建一个C风格的指针,但那是当node.next被声明为[(&#34; next&#)时应该接收的内容。 34;,nodeTypePointerType),...](在nodeType。 fields = ...)。所以我很失落。

1 个答案:

答案 0 :(得分:0)

引用eryksun的评论:

  

dictType_1.root是一个LP_InterfaceListNode字段,即POINTER(InterfaceListNode),但您要使用InterfaceListNode而不是指向一个的{I}初始化它。 &#34; LP&#34;用于&#34;长指针&#34;从分段架构的日子回来(在段内)和远/长指针。 Windows类型保留此前缀,即使它不再有意义,例如LPVOIDLPWSTR。 ctypes最初是一个仅限Windows的软件包

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

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

解决问题。

相关问题