当前位置: 首页 > 面试题库 >

在Python中包装C库:C,Cython或ctypes?

屠晟睿
2023-03-14
问题内容

我想从Python应用程序调用C库。我不想包装整个API,只包装与我的情况相关的函数和数据类型。如我所见,我有三个选择:

  1. 在C中创建一个实际的扩展模块。可能有点过头了,我还想避免学习扩展编写的开销。
  2. 使用Cython将C库的相关部分公开给Python。
  3. 使用Pythonctypes与外部库进行通信,从而完成整个工作。

我不确定2)还是3)是更好的选择。3)的优点是它ctypes是标准库的一部分,并且生成的代码将是纯Python –尽管我不确定该优点实际上有多大。

两种选择都有其他优点/缺点吗?您推荐哪种方法?

编辑: 感谢您的所有答复,它们为希望做类似事情的任何人提供了很好的资源。当然,仍需针对单个案例做出决定-
没有人会回答“这是对的”。就我自己而言,我可能会使用ctypes,但我也期待在其他项目中试用Cython。

由于没有一个单一的真实答案,因此接受一个答案多少有些武断。我选择了FogleBird的答案,因为它提供了对ctypes的一些很好的了解,并且它也是当前投票最高的答案。但是,我建议您阅读所有答案以获得一个很好的概述。

再次感谢。


问题答案:

ctypes 是快速完成任务的最佳选择,并且在仍在编写Python的情况下很高兴与您合作!

我最近包装了一个FTDI驱动程序,用于使用ctypes与USB芯片进行通信,这很棒。我完成了所有工作,并在不到一个工作日的时间内完成了工作。(我只实现了我们需要的功能,大约有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

有人对各种选项做了一些基准测试。

如果不得不包装带有许多类/模板/等的C
++库,我可能会更加犹豫。但是ctypes可以很好地与结构配合使用,甚至可以回调到Python中。



 类似资料:
  • 本文向大家介绍cython 包装DLL:从C ++到Cython到Python,包括了cython 包装DLL:从C ++到Cython到Python的使用技巧和注意事项,需要的朋友参考一下 示例 这展示了一个用Cython包装C ++ dll的简单例子。它将涵盖以下主要步骤: 使用Visual Studio使用C ++创建示例DLL。 用Cython包裹DLL,以便可以在Python中调用它。

  • 问题 你想使用Cython来创建一个Python扩展模块,用来包装某个已存在的C函数库。 解决方案 使用Cython构建一个扩展模块看上去很手写扩展有些类似, 因为你需要创建很多包装函数。不过,跟前面不同的是,你不需要在C语言中做这些——代码看上去更像是Python。 作为准备,假设本章介绍部分的示例代码已经被编译到某个叫 libsample 的C函数库中了。 首先创建一个名叫 csample.p

  • 问题内容: 我有许多C函数,我想从python调用它们。cython似乎是要走的路,但我无法真正找到实现此目的的示例。我的C函数如下所示: 我要做的就是指定前三个参数(一个字符串和两个整数),并恢复8个numpy数组(或python列表。所有双精度数组都有N个元素)。我的代码假定指针指向已分配的内存块。同样,产生的C代码应该链接到一些外部库。 问题答案: 这是一个从逻辑上将numpy数组传递给外部

  • 问题内容: 我刚刚开始熟悉Cython,尝试将一些结构从C库包装到Python方法和类。我真正不了解的是从(初始化的)C结构到相应的Python类的转换应该如何工作。我在这里想念的是什么: C头文件中的片段: 我的.pxd对应的代码段: 我的.pyx: 直到return语句的所有内容都可以正常工作。我在等中获得了正确的值。但是return语句中的强制转换似乎不正确或缺少更多信息。发出Python段

  • 问题内容: 我有一个接受回调的C ++函数,如下所示: 我想通过给它一个闭包从Cython调用此函数,即,如果我从C ++调用它,我会用lambda来完成。如果这是一个C函数,它将有一些额外的参数: 然后我只想通过的(有更详细的在这里例子)。 有没有办法以C ++的方式做更多的事情,而不必诉诸显式的? 问题答案: 我相信您的目标是将可调用的Python对象传递给接受的对象。您需要创建一些C ++代

  • 本文向大家介绍如何用C代码给Python写扩展库(Cython),包括了如何用C代码给Python写扩展库(Cython)的使用技巧和注意事项,需要的朋友参考一下 之前一篇文章里提到了利用Cython来编译Python,这次来讲一下如何用Cython给Python写扩展库。 两种语言混合编程,其中最重要的是类型的传递。 我们用一个简单的例子进行入门:这次的目标是用C语言写一个Numpy的加法和元素