我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python和C/C++交互的几种方法总结

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python和C/C++交互的几种方法总结

前言

python作为一门脚本语言,其好处是语法简单,很多东西都已经封装好了,直接拿过来用就行,所以实现同样一个功能,用Python写要比用C/C++代码量会少得多。但是优点也必然也伴随着缺点(这是肯定的,不然还要其他语言干嘛),python最被人诟病的一个地方可能就是其运行速度了。这这是大部分脚本语言共同面对的问题,因为没有编译过程,直接逐行执行,所以要慢了一大截。所以在一些对速度要求很高的场合,一般都是使用C/C++这种编译型语言来写。但是很多时候,我们既想使用python的简介优美,又不想损失太多的性能,这个时候有没有办法将python与C/C++结合到一起呢?这样在性能与速度要求不高的地方,可以用pyhton写,而关键的运算部分用C/C++写,这样就太好了。python在做科学计算或者数据分析时,这是一个非常普遍的需求。要想实现这个功能,python为我们提供了不止一种解决办法。

下面我就逐一给大家介绍。

一、Cython 混合python与C

官方网址:http://docs.cython.org/en/latest/class="lazy" data-src/quickstart/overview.html。首先来看看cython的官方介绍吧。

[Cython] is a programming language that makes writing C extensions for the Python language as easy as Python itself. It aims to become a superset of the [Python]language which gives it high-level, object-oriented, functional, and dynamic programming. Its main feature on top of these is support for optional static type declarations as part of the language. The source code gets translated into optimized C/C++ code and compiled as Python extension modules. This allows for both very fast program execution and tight integration with external C libraries, while keeping up the high programmer productivity for which the Python language is well known.

简单来说,cython就是一个内置了c数据类型的python,它是一个python的超集,兼容几乎所有的纯python代码,但是又可以使用c的数据类型。这样就可以同时使用c库,又不失python的优雅。

好了,不讲太多废话,直接来看cython如何使用吧。这里的介绍大部分来自官网,由于cython涉及到的东西还比较多,所以这里只是简单的入门介绍,详细的信息请移步英文官网。

使用cython有两种方式:第一个是编译生成Python扩展文件(有点类似于dll,即动态链接库),可以直接import使用。第二个是使用jupyter notebook或sage notebook 内联 cython代码。

先看第一种。还是举最经典的hello world的例子吧。新建一个hello.pyx文件,定义一个hello函数如下:


def hello(name):
 print("Hello %s." % name)

然后,我们来写一个setup.py 文件(写python扩展几乎都要写setup.py文件,我之前也简单介绍过怎么写)如下:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/5/8 9:09
# @Author : Lyrichu
# @Email : 919987476@qq.com
# @File : setup.py
'''
@Description: setup.py for hello.pyx
'''
from Cython.Build import cythonize
from distutils.core import setup

# 编写setup函数
setup(
 name = "Hello",
 ext_modules = cythonize("hello.pyx")
)

其中 ext_modules 里面写你要 编译的.pyx文件名字。OK,所有工作都完成了。接下来,进入cmd,切换到setup.py 所在的文件,然后执行命令: python setup.py build_ext --inplace 就会编译生成一个build 文件夹以及一个.pyd文件了,这个pyd文件就是python的动态扩展库,--inplace 的意思是在当前文件目录下生成.pyd文件,不加这一句就会在build文件夹中生成。

截图如下:

查看图片

图 1

可以看出,除了生成了一个pyd文件之外,还生成了一个.c文件。test.py是我们用来测试的文件,在里面写如下内容:


from hello import hello
hello("lyric")

从hello 模块导入 hello函数,然后直接调用就可以了。结果输出 Hello lyric.

再来看如何 在 jupyter notebook中使用cython。如果你装过ipython,一个升级版的python交互式环境,你应该听过 ipyhton notebook的大名,现在它升级了,改名叫jupyter notebook 了。简单来说,这个就是一个可以在网页环境下交互式使用python的工具,不仅可以实时看到计算结果,还可以直接展示表格,图片等,功能还是非常强大的。首先你得安装jupyter notebook.我印象中安装了ipython之后应该就会带了jupyter了。如果没有,可以直接 pip install jupyter .然后输入命令 jupyter notebook 就会在浏览器中打开jupyter了。

如下图2 所示:

查看图片

图 2

点击右上角的new按钮,可以选择新建一个文本文件或者文件夹,markdown或者python文件,这里我们选择新建一个pyhton 文件,然后就会转到一个新的窗口了,如下图3:

查看图片

图 3

In[]:和ipython一样,就代表着我们要输入代码的地方,输入代码之后,点击向右的三角形符号,就会执行代码了。

首先输入 %load_ext cython ,然后执行,%开头的语句是jupyter的魔法命令,%是行命令,%%是单元命令,具体不多说,有空给大家专门介绍一下notebook的使用。

接下来输入:


 %%cython
 cdef int a = 0
 for i in range(10):
  a += i
 print(a)

%%cython 表明将cython内嵌到jupyter,cdef 是cython的关键字,用于定义c类型,这里将a定义为c中的int类型,并且初始化为0.

然后后面的循环就是累加0到9的意思,最后输出45.

另外,我们如果想分析代码 的执行情况,可以输入 %%cython --annotate 命令,这样就可以输出结果的同时,也输出 详细的代码执行情况报告了。

截图如图4 所示:

查看图片

图 4

jupyter notebook 可以内嵌cython,不用我们手写setup.py 文件,省去了编译的过程,方便了cython的使用,所以不是正式做项目,只是写一写小东西用jupyter+cython还是非常方便的。

前面提到了 cdef,再举一个稍微复杂点的例子吧。还是引用官网的例子,写一个算积分的函数.新建 integrate.pyx 文件,写入如下内容:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/5/8 9:26
# @Author : Lyrichu
# @Email : 919987476@qq.com
# @File : integrate.py
'''
@Description: 积分运算,使用 cython cdef 关键字
'''
def f(double x):
 return x**2 - x

def integrate_f(double a,double b,int N):
 cdef int i
 cdef double s,dx
 s = 0
 dx = (b-a)/N
 for i in range(N):
  s += f(a + i*dx)*dx
 return s # 返回定积分

这段代码应该也是比较好理解的, f()函数是被积函数,a,b是积分的上下限,N是分割小矩形的个数,注意这里将 变量i,s,dx全部都用cdef 声明为c类型了,一般来说,在需要密集计算的地方比如循环或者复杂运算,可以将对应的变量声明为c类型,可以加快运行速度。

然后和上面一样编写 setup.py ,就是把 pyx的文件名改一下,代码我就不贴了。然后python setup.py build_ext --inplace 执行。得到pyd文件,编写测试文件test.py如下:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/5/8 9:35
# @Author : Lyrichu
# @Email : 919987476@qq.com
# @File : test.py
'''
@Description: 测试使用cython 混合c与python的integrate 函数与纯python写的integrate函数速度上的差异
'''
from integrate import integrate_f
import time

a = 1 # 积分区间下界
b = 2 # 积分区间上界
N = 10000 # 划分区间个数

# 使用纯python代码写的integrate函数
def py_f(x):
 return x**2 - x

def py_integrate_f(a,b,N):
 dx = (b-a)/N
 s = 0
 for i in range(N):
  s += py_f(a + i*dx)*dx
 return s

start_time1 = time.time()
integrate_f_res = integrate_f(a,b,N)
print("integrate_f_res = %s" % integrate_f_res)
end_time1 = time.time()
print(u"cython 版本计算耗时:%.8f" % (end_time1 - start_time1))

start_time2 = time.time()
py_integrate_f_res = py_integrate_f(a,b,N)
print("py_integrate_f_res = %s" % py_integrate_f_res)
end_time2 = time.time()
print(u"python 版本计算耗时:%.8f" % (end_time2 - start_time2))

上面的代码,我们重新使用python写了一个积分函数py_integrate_f,与pyd中的integrate_f 函数进行运算对比,结果如下(图5):

查看图片

图5

可以看出,使用了cython的版本比纯Python的版本大概快了4、5倍的样子,而这仅仅是将几个变量改为c类型的结果,可见,cython确实可以方便地对python与c进行混合,获得速度上的提升,又不失去Python的简洁优美。

最后再来说下cython 如何调用c libraries. C 语言 stdlib 库有一个 atoi函数,可以将字符串转化为整数,math库有一个sin函数,我们就以这两个函数为例。新建 calling_c.pyx 文件,文件内容如下:


from libc.stdlib cimport atoi
from libc.math cimport sin

def parse_char_to_int(char * s):
 assert s is not NULL,"byte string value is NULL"
 return atoi(s)

def f_sin_squared(double x):
 return sin(x*x)

前两行导入了C语言中的函数,然后我们自定义了两个函数,parse_char_to_int 可以将字符串转换为整数,f_sin_squared 计算 x平方的sin函数值。写 setup.py 文件,和之前差不多,但是要注意的是,在unix系统下,math库默认是不链接的,所以需要指明其位置,那么在unix系统下,setup.py 文件的内容就需要增加Extension 一项,如下:


from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

ext_modules=[
 Extension("calling_c",
    sources=["calling_c.pyx"],
    libraries=["m"] # Unix-like specific
 )
]

setup(
 name = "Calling_c",
 ext_modules = cythonize(ext_modules)
)

然后直接编即可。test.py文件如下:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/5/8 12:21
# @Author : Lyrichu
# @Email : 919987476@qq.com
# @File : test.py
'''
@Description: test file
'''
from calling_c import f_sin_squared,parse_char_to_int
str = "012"
str_b = bytes(str,encoding='utf-8')
n = parse_char_to_int(str_b)
print("n = %d" %n)
from math import pi,sqrt
x = sqrt(pi/2)
res = f_sin_squared(x)
print("sin(pi/2)=%f" % res)

需要注意的是,Python字符串不能直接传入 parse_char_to_int 函数,需要将其转换为 bytes 类型再传入。运行结果为:


n = 12
sin(pi/2)=1.000000

如果不想通过libc导入c语言模块,cython也允许我们自己声明c函数原型来导入,一个例子如下:


# 自己声明c函数原型
cdef extern from "math.h":
 cpdef double cos(double x)

def f_cos(double x):
 return cos(x)

使用了 extern 关键字。

每次都编写setup.py 文件,然后编译,略显麻烦。cython还提供了一种更简单的方法:pyximport。通过导入pyximport(安装cython时会自动安装),在没有引入额外的c库的情况下,可以直接调用pyx中的函数,更为直接与方便。以前面的hello 模块为例,编写好hello.py文件之后,编写一个pyximport_test.py 文件,文件内容如下:


import pyximport
pyximport.install()
import hello
hello.hello("lyric")

直接运行就会发现,确实可以正确导入hello模块。

cython的更多内容,请大家自行访问官网查看。

其他python与c/c++ 混合编程的方式主要还有 使用 ctypes,cffi模块以及swig。本来想一起写的,想想还是分开写吧,不然太长了。后续会陆续更新,敬请关注。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对编程网的支持。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python和C/C++交互的几种方法总结

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python和C/C++交互的几种方法总结

前言 python作为一门脚本语言,其好处是语法简单,很多东西都已经封装好了,直接拿过来用就行,所以实现同样一个功能,用Python写要比用C/C++代码量会少得多。但是优点也必然也伴随着缺点(这是肯定的,不然还要其他语言干嘛),pytho
2022-06-04

C#交换两个变量值的几种方法总结

这篇文章介绍了C#交换两个变量值的几种方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2022-11-13

C语言求素数的几种方式总结

这篇文章主要介绍了C语言求素数的几种方式总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2022-12-27

python导出requirements.txt的几种方法总结

这篇文章主要介绍了python导出requirements.txt的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-02-02

c++利用vector创建二维数组的几种方法总结

这篇文章主要介绍了c++利用vector创建二维数组的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2022-11-13

python字典取值的几种方法总结

这篇文章主要介绍了python字典取值的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-05-15

C++将字符串格式化的几种方式总结

这篇文章主要介绍了C++将字符串格式化的几种方式总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-01-28

python遍历 truple list dictionary的几种方法总结

实例如下:def TestDic1():dict2 ={'aa':222,11:222}for val in dict2:print valdef TestDic2():dict2 ={'aa':222,11:222}for (key,va
2022-06-04

Python去除html标签的几种方法总结

这篇文章主要介绍了Python去除html标签的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-01-03

C++产生随机数的几种方法小结

本文主要介绍了C++产生随机数的几种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-03-09

Android UI更新的几种方法总结

Android UI更新 做过Android开发的人都遇到过这样的问题:随着需求的变化,某些入口界面会出现UI的增减、内容变化和跳转界面变化等问题,这里就说明几种方法来实现 UI的更新。 1、Activity的 runOnUiThread
2022-06-06

Vue获取DOM的几种方法总结

这篇文章主要介绍了Vue获取DOM的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2022-11-13

mysql备份表的几种方法总结

MySQL备份表的方法包括:完全备份、增量备份、二进制日志备份和特定表的备份。选择最合适的方法取决于备份频率、数据库大小、活动级别、恢复时间目标和数据丢失容忍度。最佳实践包括定期备份、使用多种方法、测试恢复以及安全存储备份。
mysql备份表的几种方法总结
2024-04-02

android操作XML的几种方法总结

XML作为一种业界公认的数据交换格式,在各个平台与语言之上,都有广泛使用和实现。其标准型,可靠性,安全性......毋庸置疑。在android平台上,我们要想实现数据存储和数据交换,经常会使用到xml数据格式和xml文件。 小提示:andr
2022-06-06

遍历python字典几种方法总结(推荐)

如下所示:aDict = {'key1':'value1', 'key2':'value2', 'key3':'value3'} print '-----------dict-------------' for d in aDict:pri
2022-06-04

Python中创建字典的几种方法总结(推荐)

1、传统的文字表达式:>>> d={'name':'Allen','age':21,'gender':'male'} >>> d {'age': 21, 'name': 'Allen', 'gender': 'male'}如果你可以事先拼出
2022-06-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录