如果需要用 Python 调用 C/C++ 编写的第三方库,只需要一个脚本语言来粘合它们。这个时候,用 Python ctypes 可以很方便地实现调用。

StackOverflow 上的 Calling C/C++ from python 这个主题介绍了 ctypes 最简单的入门方法,概括如下:

  1. 如果是 C 函数库,则直接 load 这个库,然后调用即可;
  2. 如果是 C++ 函数库,则需要用 extern 关键字封装一个供 C 使用的函数,即把类隐藏到一些 C 风格的函数里,然后用 extern 标明这些函数,以方便外部调用。

这两种方法里,弄懂了 ctypes 调用 C++ 库的方法,就会用 ctypes 调用 C 函数库,对 C++ 库的基本方法如下。

例如,有一个 C++ 类 Foo:

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

再封装出下面 C 风格的接口函数:

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

,然后再用 Python 写的代码来调用这个类,你可以把上面两个 C 接口函数写成 Python 类,或是直接调用:

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)

,然后就可以在 Python 脚本里调用这个 Python 类了:

f = Foo()
f.bar() #and you will see "Hello" on the screen

在 Windows 下用 Python ctypes 的方法和上面一样,只是有下面两点需要注意一下:

  1. 在编写 Python 代码时,刚开始链接所需的动态链接库时,最好使用绝对路径来 load,以减少出错概率,加快调试速度

    在我按上面的方法编写好了上述代码时,一运行脚本,则提示如下错误信息:

    $ python Linkcpp.py
    Traceback (most recent call last):
    File "Linkcpp.py", line 2, in <module>
    lib = cdll.LoadLibrary('./LinkExample')
    File "C:\Python27\lib\ctypes\__init__.py", line 431, in LoadLibrary
    return self._dlltype(name)
    File "C:\Python27\lib\ctypes\__init__.py", line 353, in __init__
    self._handle = _dlopen(self._name, mode)
    WindowsError: [Error 126]

    这是因为我在代码里是使用了这样的代码来导入动态链接库:

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

    如果把 ./LinkExample 这句换成 Windows 下的绝对路径 E:/PythonCode/LinkCpp/LinkExample,则没有错误提示了。当然,你直接把 ./LinkExample 换成 LinkExample 也可以找到该链接库。

    所以,刚开始的时候,使用绝对路径,以确保你不会纠结于能不能找到链接库之类的问题。

    在运行上述脚本的时候,出现 WindowsError: [Error 126] 的错误,无非就是两个原因

    • 你的 DLL 没有正确地被加载;
    • 你的 DLL 依赖的其它 DLL 没有被找到或是加载失败。

    另外,注意一下,Windows 下因为库分为 lib 和 dll 两个文件,所以可以只输入库的名称即可,比如说你要链接 LinkExample.dll 库,则可以在 ctypes 里只需要声明链接名为 LinkExample 库即可。

  2. 如果是 C++ 写的库,需要用上 extern 关键字,这个和一般的供 C 调用的 C++ 库头文件是一样的

    在 extern 声明的函数里,可以使用 C++ 里 C 没有的关键字,比如我的函数就是这样声明的:

    externint linkExample(constint index, constchar* name);

    上面代码可以从 Python 调用运行。

    extern:extern可置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量或函数时,在其它模块中寻找其定义。另外,extern也可用来进行链接指定。

亲自实现

c++

g++编译 g++ -o libpycallclass.so -shared -fPIC ex.cpp

  1. #include <iostream>
    using namespace std; class TestLib
    {
    public:
    void display();
    void display(int a);
    };
    void TestLib::display() {
    cout<<"First display"<<endl;
    } void TestLib::display(int a) {
    cout<<"Second display:"<<a<<endl;
    }
    extern "C" {
    TestLib obj;
    void display() {
    obj.display();
    }
    void display_int() {
    obj.display();
    }
    }

python 调用

import ctypes
so = ctypes.cdll.LoadLibrary
lib = so("./libpycallclass.so")
print 'display()'
lib.display()
print 'display(100)'
lib.display_int(100)

参考资料:

stackoverflow.com  calling-c-c-from-python

python调用c/c++相关工具:Boost.python

二次转发:http://blog.csdn.net/suwei19870312/article/details/18181675

python作为一种胶水和c/c++的更多相关文章

  1. 学习Python的三种境界

    前言 王国维在<人间词话>中将读书分为了三种境界:"古今之成大事业.大学问者,必经过三种之境界:'昨夜西风凋碧树,独上高楼,望尽天涯路'.此第一境也.'衣带渐宽终不悔,为伊消得人 ...

  2. 从python run 和python unittest两种eclipse运行方式深入理解if __name__ == "__main__"

    在写一个简单的python测试程序的时候,发现eclipse中Run as "Python run 和 Python unittest”结果不一样?为什么会不一样? 先贴一下代码段: # - ...

  3. Python面试题之python是一种什么语言及优缺点

    1.说说python是一种什么语言? 参考答案:python是一门动态解释性的强类型定义语言 编译型vs解释型 编译型优点:编译器一般会有预编译的过程对代码进行优化.因为编译只做一次,运行时不需要编译 ...

  4. [译]Python作为一种编程语言有多强大?

    Quora上有个问题:Python作为一种编程语言有多强大? 以下是Patrycja Okowicka的回答 说实话,Python是一门强大的语言,几乎所有东西都可以用Python创建!这就是为什么它 ...

  5. 从Scratch到Python——python turtle 一种比pygame更加简洁的实现

    从Scratch到Python--python turtle 一种比pygame更加简洁的实现 现在很多学校都开设了Scratch课程,学生可以利用Scratch创作丰富的作品,然而Scratch之后 ...

  6. python selenium 三种等待方式详解[转]

    python selenium 三种等待方式详解   引言: 当你觉得你的定位没有问题,但是却直接报了元素不可见,那你就可以考虑是不是因为程序运行太快或者页面加载太慢造成了元素不可见,那就必须要加等待 ...

  7. python的6种基本数据类型--字典

    python的6种基本数据类型--字典   字典 字典的定义与特性 字典是Python语言中唯一的映射类型. 定义:{key1:value1,key2:value2} 1.键与值用冒号":& ...

  8. Python的三种格式化输出

    今天刚学了python的三种格式化输出,以前没接触过这么有趣的输出方式,现在来分享一下. #!/user/bin/env python#coding:utf-8#三种格式化输出 #第一种格式化输出na ...

  9. 转载:帮你提升 Python 的 27 种编程语言

    帮你提升 Python 的 27 种编程语言: 出处:http://www.oschina.net/translate/languages-to-improve-your-python

随机推荐

  1. Linux下的压缩zip,解压缩unzip命令详解及实例

    实例:压缩服务器上当前目录的内容为xxx.zip文件 zip -r xxx.zip ./* 解压zip文件到当前目录 unzip filename.zip ====================== ...

  2. IE6-11使用location.href提交时的链接复制到firefox或chrome时出现乱码

    这是在开发国际机票查询页时碰到的一个问题,测试工程师在IE里执行查询操作,然后把查询的url赋值到firefox的地址栏,firefox打开后就变成乱码了. 1. IE浏览器,选择出发地,出发日期等后 ...

  3. CentOS 6.3下配置iSCSI网络存储

    一.简介 iSCSI(internet SCSI)技术由IBM公司研究开发,是一个供硬件设备使用的.可以在IP协议的上层运行的SCSI指令集,这种指令集合可以实现在IP网络上运行SCSI协议,使其能够 ...

  4. 浅谈C++设计模式之单例模式

    单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 通常我们可以让一个全局变量使得一个对象被访问,但它不能防止客户实例化多个对象,一个最好的办法就是让类自身负责保护它的唯一实例,这个类可 ...

  5. 使用jMeter测试Solr服务接口

    之前一直用ab做简单的服务接口测试,ab功能强悍,使用简单,但是没有生成专题图和表格等功能,因此,我们决定使用jmeter来作为我们测试工具.接下来,我们将详细介绍jmeter使用的步骤,主要包括:j ...

  6. Stanford机器学习笔记-5.神经网络Neural Networks (part two)

    5 Neural Networks (part two) content: 5 Neural Networks (part two) 5.1 cost function 5.2 Back Propag ...

  7. POJ1129Channel Allocation[迭代加深搜索 四色定理]

    Channel Allocation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14601   Accepted: 74 ...

  8. StackOverflow发布年度开发者调查报告:JavaScript备受欢迎

    StackOverflow刚刚发布了年度开发者调查报告,访问了来自173个国家的56033名编程人员,发现几乎所有开发者都精通于JavaScript.具体说来就是,超过85%的全栈开发者.超过90%的 ...

  9. Java之单例模式

    单例模式: public class Person{ public static Person per//定义一个静态变量,用来储存当前类的对象 private Person()//构造方法私有化 { ...

  10. [No000064]python 变量命名规范

    python源码和其他一些书籍,命名各种个性,没有一个比较统一的命名规范.于是总结了一些,供参考. 模块名: 模块应该使用尽可能短的.全小写命名,可以在模块命名时使用下划线以增强可读性.同样包的命名也 ...