【问题标题】:ctypes - Beginnerctypes - 初学者
【发布时间】:2011-07-02 04:46:10
【问题描述】:

我的任务是将 c 库“包装”到 python 类中。文档在这个问题上非常模糊。似乎他们希望只有高级 python 用户才能实现 ctypes。

一些循序渐进的帮助会很棒。

所以我有我的 c 库。我该怎么办?我把什么文件放在哪里?如何导入库?我读到可能有一种“自动换行”到 Python 的方法?

(顺便说一句,我在 python.net 上做了 ctypes 教程,但它不起作用。意思是我认为他们假设我应该能够填写其余步骤。)

事实上,这是我在使用他们的代码时遇到的错误:

File "importtest.py", line 1
   >>> from ctypes import *
   SyntaxError: invalid syntax

我真的可以在这方面使用一些逐步的帮助!

【问题讨论】:

  • importtest.py 中有>>> 吗?当人们发布每行有>>> 的代码时,它表示它正在交互式shell 中运行。要从文件中运行它,请删除 >>> (即 3 个 > 符号和一个空格)出现的任何位置。
  • 不要输入>>>s。这些是由交互式 shell 打印的,应该不在源文件中。
  • >>> 在 .py 文件中!哎哟!以前从未见过!
  • 老实说,在开始使用 ctypes 之前,先学习一点 Python(至少一点点)。你永远会找到假设你不了解基本 Python 的 ctypes 教程。
  • @spentak:如果您寻求帮助,请提供足够的信息。至少向我们展示您正在谈论的最新版本的代码。例如,“第 3 行”是什么?

标签: python python-3.x ctypes


【解决方案1】:

这是一个快速而肮脏的 ctypes 教程。

首先,编写您的 C 库。这是一个简单的 Hello world 示例:

testlib.c

#include <stdio.h>

void myprint(void);

void myprint()
{
    printf("hello world\n");
}

现在将其编译为共享库 (mac fix found here):

$ gcc -shared -Wl,-soname,testlib -o testlib.so -fPIC testlib.c

# or... for Mac OS X 
$ gcc -shared -Wl,-install_name,testlib.so -o testlib.so -fPIC testlib.c

然后,使用 ctypes 编写一个包装器:

testlibwrapper.py

import ctypes

testlib = ctypes.CDLL('/full/path/to/testlib.so')
testlib.myprint()

现在执行它:

$ python testlibwrapper.py

你应该会看到输出

Hello world
$

如果您已经有了一个库,您可以跳过本教程的非 Python 部分。确保 ctypes 可以通过将其放在 /usr/lib 或其他标准目录中找到该库。如果这样做,则无需在编写包装器时指定完整路径。如果您选择不这样做,您必须在调用ctypes.CDLL() 时提供库的完整路径。

这里不是提供更全面教程的地方,但如果您就本网站上的特定问题寻求帮助,我相信社区会为您提供帮助。

PS:我假设您使用的是 Linux,因为您使用过 ctypes.CDLL('libc.so.6')。如果您使用的是其他操作系统,情况可能会发生一些变化(或变化很大)。

【讨论】:

  • @Chinmay:我可以为 Windows 提供类似的代码,而不是 C,您能否提供一个可视的 c++ 示例?我能够加载我的库,但我无法从 .dll 文件访问我的函数。它总是说“找不到功能'xyz'”。你能建议我解决这个问题吗?干杯。
  • 我对 Windows 开发不是很了解,但是看起来 Windows 做了一些很奇怪的事情,也许它使用了不同的调用约定?也许您可能会查找使用“extern C”导出您的 C++ 函数?
  • 是的,我确实这样做了,但到目前为止还没有运气。
  • 感谢简单易懂的教程,展示了 ctype 的基本功能
  • 又快又脏总是最好的教程
【解决方案2】:

Chinmay Kanchi 的答案非常好,但我想要一个函数示例,该函数将变量/数组传递并返回给 C++ 代码。我想我会把它包括在这里,以防它对其他人有用。

传递和返回一个整数

一个函数的 C++ 代码,它接受一个整数并将返回值加一,

extern "C" int add_one(int i)
{
    return i+1;
}

保存为文件test.cpp,注意required extern "C"(对于 C 代码可以删除)。 这是使用 g++ 编译的,参数类似于 Chinmay Kanchi 的答案,

g++ -shared -o testlib.so -fPIC test.cpp

Python 代码使用 numpy.ctypeslib 中的 load_library,假设共享库的路径与 Python 脚本位于同一目录中,

import numpy.ctypeslib as ctl
import ctypes

libname = 'testlib.so'
libdir = './'
lib=ctl.load_library(libname, libdir)

py_add_one = lib.add_one
py_add_one.argtypes = [ctypes.c_int]
value = 5
results = py_add_one(value)
print(results)

这会按预期打印 6。

传递和打印数组

您也可以按如下方式传递数组,让 C 代码打印数组的元素,

extern "C" void print_array(double* array, int N)
{
    for (int i=0; i<N; i++) 
        cout << i << " " << array[i] << endl;
}

它像以前一样编译并以相同的方式导入。使用此函数的额外 Python 代码将是,

import numpy as np

py_print_array = lib.print_array
py_print_array.argtypes = [ctl.ndpointer(np.float64, 
                                         flags='aligned, c_contiguous'), 
                           ctypes.c_int]
A = np.array([1.4,2.6,3.0], dtype=np.float64)
py_print_array(A, 3)

我们指定数组,print_array 的第一个参数,作为指向对齐的、c_contiguous 64 位浮点数的 Numpy 数组的指针,第二个参数作为一个整数,它告诉 C 代码 Numpy 中的元素数量大批。然后由 C 代码打印如下,

1.4
2.6
3.0

【讨论】:

  • 这是一个很好的补充答案 - 可惜不能有两个勾选的答案:(
  • 不确定是不是太明显了,但是代码有错误。它缺少import numpy as np。否则它无法找到np.float64 和其他东西。
  • 同样,包含print_array()的.cpp文件需要#include &lt;iostream&gt;using namespace std;。否则无法找到coutendl
  • 男人中的神。男人是那些使事情复杂化并模糊基本面以使自己看起来像神的生物。
【解决方案3】:

首先:您在 python 示例中看到的&gt;&gt;&gt; 代码是一种表明它是 Python 代码的方式。它用于将 Python 代码与输出分开。像这样:

>>> 4+5
9

在这里,我们看到以&gt;&gt;&gt; 开头的行是 Python 代码,而 9 是它的结果。如果您启动 Python 解释器,这正是它的外观,这就是它这样做的原因。

您永远不会将&gt;&gt;&gt; 部分输入到.py 文件中。

这可以解决您的语法错误。

其次,ctypes 只是包装 Python 库的几种方法之一。其他方式是SWIG,它将查看您的 Python 库并生成一个暴露 C API 的 Python C 扩展模块。另一种方法是使用Cython

它们都有优点和缺点。

SWIG 只会将你的 C API 暴露给 Python。这意味着您没有得到任何对象或任何东西,您必须创建一个单独的 Python 文件来执行此操作。然而,通常有一个名为“wowza”的模块和一个名为“_wowza”的 SWIG 模块,它是 C API 的包装器。这是一种很好且简单的做事方式。

Cython 生成一个 C 扩展文件。它的好处是你编写的所有 Python 代码都用 C 语言编写,因此你编写的对象也是 C 语言,这可以提高性能。但是您必须了解它如何与 C 接口,因此学习如何使用它需要做一些额外的工作。

ctypes 的好处是无需编译 C 代码,因此可以很好地用于包装其他人编写的标准库,并且已经存在于 Windows 和 OS X 的二进制版本中。

【讨论】:

    猜你喜欢
    • 2022-01-17
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多