Python的一个内嵌C++扩展生成器。
copperhead的Python项目详细描述
铜斑蛇
蟒蛇-gt;蛇-gt;CoppHead & gt;<强> c>强> o>强> pp强> Erth-& Gt;<强> CPP -gt;<强> C++< /强>
简介
<代码> CoppHead 是一个动态代码生成器,允许在Python中编写和执行C++代码块。最后,使用setuptools将代码包装并内置到模块中。copperhead
非常适合原型制作和"假设"探索。我不一定建议直接将它用于生产代码和环境,但它有助于开发生产/发布级模块和库。
安装
对于最新版本(目前唯一的版本是prerelease!)
pip install copperhead
对于最新的开发人员,克隆此存储库并:
python setup.py install
<代码> CoppHead 将使用用于构建Python安装的编译器,等等,您可能会遇到旧的系统,直到我实现一种方法来传递编译器标志(可能是将C++标准还原为更旧的;现在默认为C++ 14)。
动机
首先也是最重要的一点是,我想了解更多关于python c api的知识(这是我多年来才真正接触到的东西)。我也在看cppcon视频(这一个特别),而当他(Chandler Carruth)开始与他的C++进行联机书写时,我着迷了。我从来没有用C++在低水平上工作过,这让我有点心烦。我心里想,"如果我可以用我的Python写我的C++呢?"。所以我们今天到了。
<代码> CoppHead 生成香草C++代码,而不依赖于第三方C++库。这是在python中完成的,而不是从本机库或一组头文件中完成的。这很重要,因为它意味着你可以专注于编写C++,而不是在一组本地绑定、构建系统等的样板上编写。就是这样当你使用<代码> CoppHead 时,你只剩下原始的 C++和Studio.Py < /e>文件,用来生成扩展名。这意味着你有一些具体的、可重用的、可调整的等等,它们是纯标准C++和标准Python。你想说什么就说什么,但这可能是关于铜斑蛇的最好部分。
<代码> CoppHead 通过在一个新的Python API启用的函数中自动包装C++代码,并将其与必要的代码配对,将其打包到与Python兼容的模块中。此过程有三个主要步骤: 函数包装器是最复杂的组件。<代码> CoppHead 将检查所提供的函数类型的返回类型和参数类型,并将生成从Python输入转换为C++类型所需的所有变量,调用函数,并将其转换为Python类型。 该模块目前相当cookie,简单地包含了C++函数、包装器和制作模块的所有样板。
安装脚本只是一个setup.py脚本,我们用一些数据填充它,这里没有什么特别的。 新创建的setup.py脚本用于生成模块。它将在一个目录中本地转储新模块名为的ectory.copperhead_cache。你的路径将被调整以包含新生成的卵子。如果egg已经存在,则跳过此过程,只需导入已经可用的内容。注意,返回的是函数而不是模块。工作原理
代码生成
开发环境
我用最新的Python和现代C++技术编写代码。我对向后兼容性没有兴趣。虽然早期的版本和标准现在可能可以工作,但我不保证会有任何进展。我不会为了支持老的东西而阻碍发展。考虑到目前我可以使用的开发环境的范围,有一点兼容性。
我目前有一些主要的开发环境,因此您可以期望至少支持以下内容:
- python 3.6.7和gcc 7.3.0(ubuntu 18.04.2)
- <强> Python 3.68和MSVC V1916(Windows 10,Visual C++ 2017(15.9)) < < > > >强> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
- python 3.7.3和gcc 6.3.0(raspbian)
基本用法
你好,世界!
下面是一个简单的示例,演示如何创建典型的hello world!
程序:importcopperheadascpphello_world_cpp='''#include <iostream>void hello_world(){ std::cout << "Hello World!" << std::endl;}'''hello_world=cpp.generate('hello_world','void()',hello_world_cpp)hello_world()
STL支持
现在提供了基本的stl支持,并有了更多的计划。STD:STD:STD::队列, STD::Deq作为返回和参数类型,并可以相互嵌套。
importcopperheadascppstd_vector_cpp='''#include <iostream>#include <vector>void vprint(std::vector<int> v){ for (auto i : v) { std::cout << i << " "; } std::cout << std::endl;}'''vprint=cpp.generate('vprint','void(std::vector<int>)',std_vector_cpp)vprint([1,2,3,4,5])
曼德尔布罗特
要生成mandelbrot集吗?令人惊叹的!您可以使用它并编写一个简单的实现来生成一个文件,其中包含转义时间:
defmandlebrot(c):max_iter=100i=0z=0.0jwhileabs(z)<2.0andi<max_iter:z=z*z+ci+=1returnmax_iter-ix=-2.0y=1.25h=0.0005n=int(2.5/h)withopen('fractal.dat','w')asf:foryidxinrange(n):forxidxinrange(n):f.write('{} '.format(mandlebrot(complex(x,y))))x+=hf.write('\n')y-=hx-=2.5
如果这是你想要的实现,那就好。在我的系统中,运行大约需要1分40秒。但是,我不想等待超过2分钟来运行此设置,并且按比例,此设置会变得更糟。缓冲输出有潜在的问题,也许我们可以做一些其他的微观优化,但是这些改进并不是实质性的,它们并不能解决我们的性能问题。排队输入铜斑蛇
大量的迭代和大量的输出。听起来像C++的东西,对吧?让我们实现一个类似的功能: 在开始对python进行评估之前,请注意我决定让这个输入驱动。我们可以指定函数的返回类型和参数类型,以便我们可以传入数据。在这里,我们指定输出文件名和一些参数,这些参数指示我们所关心的集合的区域和迭代的粒度。 运行这个,你会看到一个很好的术语被转储到StdOUT:这是C++扩展的创建(再次运行,缓存被访问,而你将看不到它)。在我的系统中,这大约需要9秒钟。1:40到0:09。随着问题空间的扩大,这里的改进变得更大。虽然时间并不是一个有价值的基准,但这里的储蓄太大,太明显,不容忽视。 请注意,此存储库中的示例代码使用 有关详细信息,请参见license.md,但它是麻省理工学院的许可证。 :importcopperheadascppmandelbrot_cpp=r'''#include <cmath>#include <complex>#include <fstream>inline int mandelbrot(const std::complex<double> &c){ const int max_iter {100}; int i {0}; std::complex<double> z {0.0, 0.0}; while (std::abs(z) < 2.0 && i < max_iter) { z = z * z + c; ++i; } return max_iter - i;}void compute(std::string filename, double x, double y, double h){ const auto n {std::lround(2.5 / h)}; std::ofstream f(filename); for (long yidx {0}; yidx < n; ++yidx) { for (long xidx {0}; xidx < n; ++xidx) { f << mandelbrot(std::complex<double>(x, y)) << " "; x += h; } f << "\n"; y -= h; x -= 2.5; }}'''compute=cpp.generate('compute','void(std::string, double, double, double)',mandelbrot_cpp)compute('fractal.dat',-2.0,1.25,0.0005)
h=0.005
来减少测试期间的运行时间。许可证
待办事项
推荐PyPI第三方库