使用ctypes调用c语言接口+使用virtualenv隔离python环境

文章内容为原创,欢迎转载请注明出处

今天的睿普小课堂主要为大家分享,如何使用ctypes调用c语言接口+使用virtualenv隔离python环境

Part 1 使用ctypes调用c语言接口

1.背景

python作为解析语言大规模应用在各个领域,c语言作为系统级别的语言广泛应用在基础,系统,网络等底层服务当中,可以说python和c语言之间各有擅长和不擅长的地方,今天文章讨论的是,如何使用python开发的程序调用c语言写的库文件,使得两种语言得以互补。

2.ctypes

ctypes是python自带的用于跟c语言做对接的库,里面提供了针对c语言数据类型,除此还提供了加载动态库和调用动态库函数的功能,比如在windows下可以加载dll文件并可以调用里面的函数接口,在linux下可以加载so文件调用里面的函数接口。

3.例子

我们使用ctypes库,调用c语言经常用到的printf函数作为一个简单的例子,下面是具体python代码

>>> import ctypes

>>> ctypes.cdll.LoadLibrary('libc.so.6')

>>> libc = ctypes.CDLL('libc.so.6')

>>> libc.printf

>>> libc.printf("hello %s\n", "world!")

hello world!

13

>>>

简单解析一下上面的几行代码,我们知道printf函数是c语言基础库,放在libc.so文件里面,以例子所在Ubuntu 16.04 x64 Server,具体路径是 /lib/x86_64-linux-gnu/libc.so.6,首先是用ctypes加载对应的so文件,因为libc是系统基础库文件,所以不用指定绝对路径,加载完之后就实例化libc的对象,比如程序的libc,然后就可以调用libc里面的printf函数了。根据printf的函数原型,除了输出字符信息之外,还返回输出信息的长度,所以我们看到除了输出hello world!之外,下面返回的14就是字符串的长度。

4.实战

上面3的例子是调用系统自带的库,下面我们自己尝试用c语言编写一个动态库,然后使用ctypes调用里面的函数接口。我们先用c语言编写一个最简单的库,然后这个库里面只有一个函数接口。

foo.h

#ifndef foo_h__

#define foo_h__

extern void foo(void);

#endif // foo_h__

foo.c

#include

void foo(void)

{

printf("Hello, I'm a shared library");

}

编译foo so动态库

gcc -c -Wall -Werror -fpic foo.c

gcc -shared -o libfoo.so foo.o

一切顺利的话,当前目录下会有一个libfoo.so的动态库文件,下面我们写一个main.c的程序测试一下这个libfoo.so库

main.c

#include

#include "foo.h"

int main(void)

{

printf("This is a shared library test...");

foo();

return 0;

}

编译main.c文件

#这里需要用-L参数告诉gcc我们的so库所在目录,要不gcc会找不到我们的库

gcc -L/tmp/test -Wall -o test main.c -lfoo

一切顺利之后会产生test的执行文件,我们执行它,不过执行之前我们先要定义一下系统库路径,要不执行test的时候系统会提示找不到库文件

export LD_LIBRARY_PATH=/tmp/test:$LD_LIBRARY_PATH

./test

顺利输出信息。我们知道我们的libfoo.so是正常可用的,那么我们就写一个python程序去调用我们的libfoo里面的foo函数接口。

main.py

>>> import ctypes

>>> ctypes.cdll.LoadLibrary('/tmp/test/libfoo.so')

>>> libfoo = ctypes.CDLL('libfoo.so')

>>> libfoo = ctypes.CDLL('/tmp/test/libfoo.so')

>>> libfoo

>>> libfoo.foo()

Hello, I'm a shared library27

>>>

具体代码其实跟3.例子类似,只是因为我们的库是非系统的,所以要指定绝对路径而已,字符串最后的27是输出字符串的长度。

Part 2 使用virtualenv隔离python环境

1.背景

在开发python项目中,我们可能会遇到一种场景,在同一台机器上的python运行环境需要隔离,特别是在多人使用和存在不同版本库情况下,比如A开发人员用了库1.0,B开发人员用了库2.0,为了使系统默认的python环境不受污染,需要一个工具,能对python开发运行环境进行有效隔离。

2.virtualenv

virtualenv则是解决了python开发运行环境隔离问题的一种解决方案,具体可以参考官网

virtualenv实现了安装包的隔离,在某一环境下安装包不会影响其他的环境,还可以针对不同的环境设置不同版本的python解析器,比如可以选择python2的,也可以选择python3,下面我们通过简单的例子来示范virtualenv的安装与使用。

3.安装与使用

安装virtualenv很简单,只需要使用python包管理工具pip安装即可。

pip install virtualenv

安装顺利完成之后,我们可以开始创建python运行环境了。

#我们在/tmp目录下进行我们的示范试验

cd /tmp

mkdir test

cd test

#先创建一个test01的环境

virtualenv test01

#再创建一个test02的环境

virtualenv test02

#我们可以使用ls命令,可以看到test01,test02文件夹下面都有各自的python运行环境所需要的目录和文件

ls test01

ls test02

#下面我们演示设置不同python解析器,默认情况下采用的是python2,我们对test02设置采用python3的解析器

virtualenv -p /usr/bin/python3.5 test02

#在使用test01,test02环境之前,我们需要执行激活脚本

#使用test01环境

source test01/bin/activate

#执行完后,你会发现终端名称发生了变化,比如本机返回

(test01) root@iZwz9fz5sbmqiuiukgse8pZ:/tmp/test#

#这样我们就可以清晰得知当前是在test01环境下,我们看看python版本号

python -V

#返回以下内容

Python 2.7.12

#执行deactivate退出当前环境回到普通终端状态

deactivate

#我们再进去test02环境看看

source test02/bin/activate

#返回终端切换成test02

(test02) root@iZwz9fz5sbmqiuiukgse8pZ:/tmp/test#

#查看python解析器版本

python -V

#返回以下内容

Python 3.5.2

#从上面的实例,我们可以看到使用virtual确实实现了python运行环境的隔离,下面我们在不同环境下安装包看看是否隔离

#我们在test02环境下用pip安装daemon库

(test02) root@iZwz9fz5sbmqiuiukgse8pZ:/tmp/test# pip install daemon

#安装成功后,我们看看当前安装的库

(test02) root@iZwz9fz5sbmqiuiukgse8pZ:/tmp/test# pip list

appdirs (1.4.3)

daemon (1.1)

packaging (16.8)

pip (9.0.1)

pyparsing (2.2.0)

setuptools (35.0.1)

six (1.10.0)

wheel (0.29.0)

#我们看到test02环境已经安装了daemon库了,我们切换过去test01环境,看看

appdirs (1.4.3)

packaging (16.8)

pip (9.0.1)

pyparsing (2.2.0)

setuptools (35.0.1)

six (1.10.0)

wheel (0.29.0)

#我们可以看到test01环境没有daemon,证明环境的包是隔离的

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180409G182BC00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券