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兼容的模块中。此过程有三个主要步骤:

  1. 生成函数包装器
  2. 生成模块
  3. 生成设置脚本
  4. < > >

    函数包装器是最复杂的组件。<代码> CoppHead 将检查所提供的函数类型的返回类型和参数类型,并将生成从Python输入转换为C++类型所需的所有变量,调用函数,并将其转换为Python类型。

    该模块目前相当cookie,简单地包含了C++函数、包装器和制作模块的所有样板。

    安装脚本只是一个setup.py脚本,我们用一些数据填充它,这里没有什么特别的。

    < H3>安装和导入C++模块

    新创建的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++的东西,对吧?让我们实现一个类似的功能:

    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)

    在开始对python进行评估之前,请注意我决定让这个输入驱动。我们可以指定函数的返回类型和参数类型,以便我们可以传入数据。在这里,我们指定输出文件名和一些参数,这些参数指示我们所关心的集合的区域和迭代的粒度。

    运行这个,你会看到一个很好的术语被转储到StdOUT:这是C++扩展的创建(再次运行,缓存被访问,而你将看不到它)。在我的系统中,这大约需要9秒钟。1:40到0:09。随着问题空间的扩大,这里的改进变得更大。虽然时间并不是一个有价值的基准,但这里的储蓄太大,太明显,不容忽视。

    请注意,此存储库中的示例代码使用h=0.005来减少测试期间的运行时间。

    许可证

    有关详细信息,请参见license.md,但它是麻省理工学院的许可证。

    待办事项

    • 更多自述文件更新
    • 动态生成包装函数
      • 支持更简单的类型(各种字符类型?)
      • STD:容器STD:容器STRIN(STD::MAP,STD::unOrdEdjmap,STD::数组)
      • 支持cv限定符、指针和引用
      • 改进错误处理
    • 添加对每个要生成的调用公开多个函数的支持
    • 在缓存中开发唯一性,而不是基于名称
    • 添加配置布尔期权
      • 编译器标志
      • 链接标志
      • 其他包括
    • 在Python和C++之间提供官方基准测试结果

    欢迎加入QQ群-->: 979659372 Python中文网_新手群

    推荐PyPI第三方库


热门话题
java为什么hashmap对整数值求和   使用copyFromRealm发送副本时,从错误线程访问java领域异常   java NDK支持是一个实验性的特性,所有用例都还不支持。Android Studio中的错误?   Java从resultSet生成查询并执行新查询   youtube如何使用Java+Google数据API测量上传比特率   如何从Java调用Xtend代码?   在java中,如何清除每个方法中的字节[]数组以保护值不被内存转储?   java UTF8编码与Base64编码   (与java inorder一起提供的反应式处理和反应式反应器:MWIO.3)   带toString的java Building 9x9   java如何在GridLayout中根据手机屏幕对齐按钮?   将字符串值解析为整数时出现java错误   java activeMQ接收器倒带丢失?   jfree图表中范围标记标签的java包装文本   java Android播放列表查询不准确。。。?   当请求中的头{“Accept”:“application/octetstream”}出现错误时,java返回JSON   javanet。ucanaccess。jdbc。UcanaccessSQLException   java Hibernate注释用于自动增量,但如果在保存之前设置了值,则还应保存该值