Py学习  »  Python

如何在Python中使用C库?

Tommy • 4 年前 • 1400 次点击  

(如果这很重要,我正在使用Windows。)

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/53350
 
1400 次点击  
文章 [ 15 ]  |  最新文章 4 年前
Garfield
Reply   •   1 楼
Garfield    4 年前

我喜欢CPpyy,它非常容易用C++代码扩展Python,在需要时显著提高性能。

这里是一个示例,说明如何创建一个NUMPY数组并将其传递给C++中的类成员函数。

import cppyy
cppyy.add_include_path("include")
cppyy.include('mylib/Buffer.h')


s = cppyy.gbl.buffer.Buffer()
numpy_array = np.empty(32000, np.float64)
s.get_numpy_array(numpy_array.data, numpy_array.size)

在C++中:

struct Buffer {
  void get_numpy_array(int beam, double *ad, int size) {
    // fill the array
  }
}

Yaroslav Nikitenko
Reply   •   2 楼
Yaroslav Nikitenko    4 年前

首先你应该决定你的特殊目的是什么。关于 extending and embedding the Python interpreter 上面提到过,我可以加一个很好的 overview of binary extensions . 用例可以分为三类:

  • 加速器模块 :要比在CPython中运行的等效纯Python代码运行得更快。
  • :将现有的C接口暴露给Python代码。
  • 低级系统访问

为了给其他感兴趣的人提供一个更广阔的视角,因为你最初的问题有点模糊(“到C或C++库”),我认为这些信息可能对你很有意思。在上面的链接中,您可以阅读使用二进制扩展的缺点及其替代方法。

除了建议的其他答案外,如果您需要加速器模块,可以尝试 Numba

nicodjimenez
Reply   •   3 楼
nicodjimenez    8 年前

Cython绝对是一种方法,除非您希望编写Java包装器,在这种情况下SWIG可能更可取。

runcython 命令行工具,它使得使用Cython的过程非常简单。如果你需要把结构化的数据传递给C++,看看谷歌的ToBuFF库,非常方便。

下面是我使用这两种工具制作的一个最小示例:

https://github.com/nicodjimenez/python2cpp

Chris Andrew Edgecombe
Reply   •   4 楼
Chris Andrew Edgecombe    4 年前

其中一个Python官方文档包含 extending Python using C/C++ 即使没有使用 SWIG ,它非常简单,在Windows上运行得非常好。

Palec Jadav Bheda
Reply   •   5 楼
Palec Jadav Bheda    8 年前

问题是,如果我理解正确,如何从Python调用C函数。那么,最好的选择是Ctypes(顺便说一句,在所有Python变体中都是可移植的)。

>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19

有关详细指南,请参阅 my blog article .

mrgloom
Reply   •   6 楼
mrgloom    10 年前

我认为python的cffi是一种选择。

目标是从Python调用C代码。你应该可以这么做 不学第三语言:每一种选择都要求你 学习他们自己的语言(Cython,SWIG)或API(ctypes)。所以我们试着 你需要学习的API。

http://cffi.readthedocs.org/en/release-0.7/

Chris Andrew Edgecombe
Reply   •   7 楼
Chris Andrew Edgecombe    4 年前

我从来没用过,但我听到了一些好消息 ctypes extern "C" . 谢谢你的评论,弗洛里安·博什。

Wim Lavrijsen
Reply   •   8 楼
Wim Lavrijsen    6 年前

对于现代C++,使用CPPYY: http://cppyy.readthedocs.io/en/latest/

它基于CLAN,CLAN/LLVM的C++解释器。绑定处于运行时,不需要额外的中间语言。多亏了Clang,它支持C++ 17。

使用pip安装:

    $ pip install cppyy

    $ cat foo.h
    class Foo {
    public:
        void bar();
    };

    $ cat foo.cpp
    #include "foo.h"
    #include <iostream>

    void Foo::bar() { std::cout << "Hello" << std::endl; }

编译它:

    $ g++ -c -fPIC foo.cpp -o foo.o
    $ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

使用它:

    $ python
    >>> import cppyy
    >>> cppyy.include("foo.h")
    >>> cppyy.load_library("foo")
    >>> from cppyy.gbl import Foo
    >>> f = Foo()
    >>> f.bar()
    Hello
    >>>

支持自动加载准备好的反射信息和cmake片段来创建大型项目,以便安装包的用户可以简单地运行:

    $ python
    >>> import cppyy
    >>> f = cppyy.gbl.Foo()
    >>> f.bar()
    Hello
    >>>

由于LLVM,高级特性是可能的,例如自动模板实例化。继续示例:

    >>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
    >>> v.push_back(f)
    >>> len(v)
    1
    >>> v[0].bar()
    Hello
    >>>

Peter Mortensen Yuval F
Reply   •   9 楼
Peter Mortensen Yuval F    6 年前

This paper, claiming Python to be all a scientist needs ,基本上是说:首先用Python创建所有东西的原型。然后当你需要加速一个部分时,使用SWIG并把这个部分翻译成C。

Tom Wenseleers
Reply   •   10 楼
Tom Wenseleers    6 年前

还有 pybind11 ,这就像是 Boost.Python 与所有现代C++编译器兼容:

https://pybind11.readthedocs.io/en/latest/

Peter Mortensen Yuval F
Reply   •   11 楼
Peter Mortensen Yuval F    6 年前

退房 pyrex Cython . 它们是介于C/C++和Python之间的Python语言。

Peter Mortensen Yuval F
Reply   •   12 楼
Peter Mortensen Yuval F    6 年前

我从Python & lt;-& gt;C++绑定开始这个页面,目的是链接高级数据类型(多维STL向量和Python列表):

尝试了基于两者的解决方案 ctypes boost.python (而且不是软件工程师)我发现当需要高级数据类型绑定时它们很复杂,而我发现 SWIG

因此,这个例子使用SWIG,并且已经在Linux中进行了测试(但是SWIG是可用的,并且在Windows中也被广泛使用)。

目的是使一个C++函数可用于Python,该函数采用一个2D STL向量形式的矩阵,并返回每行的平均值(作为1D STL向量)。

#include <vector>
#include "code.h"

using namespace std;

vector<double> average (vector< vector<double> > i_matrix) {

  // Compute average of each row..
  vector <double> averages;
  for (int r = 0; r < i_matrix.size(); r++){
    double rsum = 0.0;
    double ncols= i_matrix[r].size();
    for (int c = 0; c< i_matrix[r].size(); c++){
      rsum += i_matrix[r][c];
    }
    averages.push_back(rsum/ncols);
  }
  return averages;
}

等效标题(“code.h”)为:

#ifndef _code
#define _code

#include <vector>

std::vector<double> average (std::vector< std::vector<double> > i_matrix);

#endif

我们首先编译C++代码来创建一个对象文件:

g++ -c -fPIC code.cpp

然后我们定义 SWIG interface definition file

%module code
%{
#include "code.h"
%}
%include "std_vector.i"
namespace std {

  /* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
  %template(VecDouble) vector<double>;
  %template(VecVecdouble) vector< vector<double> >;
}

%include "code.h"

使用SWIG,我们从SWIG接口定义文件生成C++接口源代码。

swig -c++ -python code.i

g++ -c -fPIC code_wrap.cxx  -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o

我们现在可以在Python脚本中使用该函数:

#!/usr/bin/env python

import code
a= [[3,5,7],[8,10,12]]
print a
b = code.average(a)
print "Assignment done"
print a
print b
mmohaveri Ben Hoffstein
Reply   •   13 楼
mmohaveri Ben Hoffstein    8 年前

最快的方法是使用 SWIG

SWIG的示例 tutorial :

/* File : example.c */
int fact(int n) {
    if (n <= 1) return 1;
    else return n*fact(n-1);
}

/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern int fact(int n);
%}

extern int fact(int n);

在Unix上构建Python模块:

swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so

用法:

>>> import example
>>> example.fact(5)
120

请注意,必须使用python-dev。在某些系统中,python头文件将基于安装方式位于/usr/include/python2.7中。

从教程中:

SWIG是一个相当完整的C++编译器,支持几乎所有的语言特征。这包括预处理、指针、类、继承,甚至C++模板。SWIG还可以用于在目标语言中将结构和类打包成代理类,以非常自然的方式公开底层功能。

Ciro Santilli 新疆改造中å
Reply   •   14 楼
Ciro Santilli æ–°ç–†æ”¹é€ ä¸­å    5 年前

ctypes 是标准库的一部分,因此比 swig problems .

对于ctypes,您需要满足对python的任何编译时依赖性,并且绑定将在任何具有ctypes的python上工作,而不仅仅是针对ctypes编译的python。

假设您有一个简单的C++示例类,您想在一个名为Foo.CPP的文件中进行对话:

#include <iostream>

class Foo{
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
};

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

接下来,您必须将其编译为共享库

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()

    def bar(self):
        lib.Foo_bar(self.obj)

一旦你拥有了它,你可以称之为

f = Foo()
f.bar() #and you will see "Hello" on the screen
Peter Mortensen Yuval F
Reply   •   15 楼
Peter Mortensen Yuval F    6 年前

你应该看看 Boost.Python . 以下是他们网站上的简短介绍:

Boost Python库是连接Python和 C++。它允许您快速和无缝地显示C++类。 函数和对象到Python,反之亦然,不使用特殊的 非侵入式的,这样您就不必更改C++代码了。 所有这些都是为了包装它,使Boost.Python成为公开 Python的第三方库。图书馆对高级语言的使用 包装代码具有一种声明性接口的外观 定义语言(IDL)。