社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

如何在Python中使用C库?

Tommy • 5 年前 • 2260 次点击  

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

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

我喜欢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    6 年前

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

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

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

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

nicodjimenez
Reply   •   3 楼
nicodjimenez    9 年前

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

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

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

https://github.com/nicodjimenez/python2cpp

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

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

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

问题是,如果我理解正确,如何从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    11 年前

我认为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    5 年前

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

Wim Lavrijsen
Reply   •   8 楼
Wim Lavrijsen    7 年前

对于现代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    7 年前

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

Tom Wenseleers
Reply   •   10 楼
Tom Wenseleers    7 年前

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

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

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

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

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

我从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    9 年前

最快的方法是使用 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 æ–°ç–†æ”¹é€ ä¸­å    6 年前

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    7 年前

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

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