我想从Python应用程序调用一个C库.我不想包装整个API,只包装与我的 case 相关的函数和数据类型.在我看来,我有三个 Select :

  1. 用C语言创建一个实际的扩展模块.可能有些过头了,我还想避免学习扩展写作的开销.
  2. 使用Cython将C库中的相关部分公开给Python.
  3. 用Python完成整个过程,使用ctypes与外部库通信.

I'm not sure whether 2) or 3) is the better choice. The advantage of 3) is that ctypes is part of the standard library, and the resulting code would be pure Python – although I'm not sure how big that advantage actually is.

两种 Select 都有更多的优点/缺点吗?你推荐哪种方法?


Edit: Thanks for all your answers, they provide a good resource for anyone looking to do something similar. The decision, of course, is still to be made for the single case—there's no one "This is the right thing" sort of answer. For my own case, I'll probably go with ctypes, but I'm also looking forward to trying out Cython in some other project.

由于没有单一的真实答案,接受一个答案多少有些武断;我 Select 了FogleBird的答案,因为它提供了对ctypes的一些很好的见解,而且它目前也是投票率最高的答案.然而,我建议阅读所有答案,以获得一个良好的概述.

再次感谢您.

推荐答案

ctypes是您快速完成工作的最佳 Select ,而且由于您仍在编写Python,因此使用ctypes是一种愉快的工作!

我最近打包了一个使用ctype与USB芯片通信的FTDI驱动程序,它非常棒.我都做完了,不到一个工作日就上班了.(我只实现了我们需要的函数,大约15个函数).

我们之前使用的第三方模块PyUSB也是出于同样的目的.PyUSB是一个实际的C/Python扩展模块.但是PyUSB在执行阻塞读/写操作时没有释放GIL,这给我们带来了问题.因此,我使用ctypes编写了我们自己的模块,它在调用本机函数时会释放GIL.

需要注意的一点是,ctypes不知道您正在使用的库中的#define个常量和内容,只知道函数,所以您必须在自己的代码中重新定义这些常量.

下面是一个代码最终看起来如何的示例(很多代码被剪掉了,只是想告诉你它的要点):

from ctypes import *

d2xx = WinDLL('ftd2xx')

OK = 0
INVALID_HANDLE = 1
DEVICE_NOT_FOUND = 2
DEVICE_NOT_OPENED = 3

...

def openEx(serial):
    serial = create_string_buffer(serial)
    handle = c_int()
    if d2xx.FT_OpenEx(serial, OPEN_BY_SERIAL_NUMBER, byref(handle)) == OK:
        return Handle(handle.value)
    raise D2XXException

class Handle(object):
    def __init__(self, handle):
        self.handle = handle
    ...
    def read(self, bytes):
        buffer = create_string_buffer(bytes)
        count = c_int()
        if d2xx.FT_Read(self.handle, buffer, bytes, byref(count)) == OK:
            return buffer.raw[:count.value]
        raise D2XXException
    def write(self, data):
        buffer = create_string_buffer(data)
        count = c_int()
        bytes = len(data)
        if d2xx.FT_Write(self.handle, buffer, bytes, byref(count)) == OK:
            return count.value
        raise D2XXException

有人在各种选项上做了some benchmarks次.

如果我不得不用大量的类/模板来包装C++库,我可能会更加犹豫,但是cType与 struct 非常好,甚至可以callback到Python.

Python相关问答推荐

替换字符串中的多个重叠子字符串

如何使用Python将工作表从一个Excel工作簿复制粘贴到另一个工作簿?

如何检测背景有噪的图像中的正方形

在Python Attrs包中,如何在field_Transformer函数中添加字段?

发生异常:TclMessage命令名称无效.!listbox"

如何在python polars中停止otherate(),当使用when()表达式时?

如何使Matplotlib标题以图形为中心,而图例框则以图形为中心

为什么numpy. vectorize调用vectorized函数的次数比vector中的元素要多?

如何排除prefecture_related中查询集为空的实例?

Python—转换日期:价目表到新行

计算空值

如何从pandas DataFrame中获取. groupby()和. agg()之后的子列?

Js的查询结果可以在PC Chrome上显示,但不能在Android Chrome、OPERA和EDGE上显示,而两者都可以在Firefox上运行

当输入是字典时,`pandas. concat`如何工作?

如何编辑此代码,使其从多个EXCEL文件的特定工作表中提取数据以显示在单独的文件中

为什么在Python中00是一个有效的整数?

类型对象';敌人';没有属性';损害';

try 使用RegEx解析由标识多行文本数据的3行头组成的日志(log)文件

是否将列表分割为2?

运行从Airflow包导入的python文件,需要airflow实例?