天天看點

混合程式設計:如何用python11調用C++

摘要:在實際開發過程中,免不了涉及到混合程式設計,比如,對于python這種腳本語言,性能還是有限的,在一些對性能要求高的情景下面,還是需要使用c/c++來完成。

那怎樣做呢?我們能使用pybind11作為橋梁,pybind11的優點是對C++ 11支援很好,API比較簡單,現在我們就簡單記下Pybind11的入門操作。

1. pybind11簡介與環境安裝

Pybind11 是一個輕量級隻包含頭檔案的庫,用于 Python 和 C++ 之間接口轉換,可以為現有的 C++ 代碼建立 Python 接口綁定。Pybind11 通過 C++ 編譯時的自省來推斷類型資訊,來最大程度地減少傳統拓展 Python 子產品時繁雜的樣闆代碼, 已經實作了 STL 資料結構、智能指針、類、函數重載、執行個體方法等到Python的轉換,其中函數可以接收和傳回自定義資料類型的值、指針或引用。

直接使用pip安裝

pip3 install pybind11

由于pybind11依賴于pytest,是以在安裝前需要先把pytest給安裝上

pip3 install pytest      

2. 求和函數

首先,我們編寫一個C++源檔案,命名為example.cpp。

// pybind11 頭檔案和命名空間
#include <pybind11/pybind11.h>
namespace py = pybind11;

int add(int i, int j)
{
    return i + j;
}

PYBIND11_MODULE(example, m)
{
    // 可選,說明這個子產品是做什麼的
    m.doc() = "pybind11 example plugin";
    //def( "給python調用方法名", &實際操作的函數, "函數功能說明" ). 其中函數功能說明為可選
    m.def("add", &add, "A function which adds two numbers", py::arg("i")=1, py::arg("j")=2);
}      

PYBIND11_MODULE()宏函數将會建立一個函數,在由Python發起import語句時該函數将會被調用。子產品名字“example”,由宏的第一個參數指定(千萬不能出現引号)。第二個參數"m",定義了一個py::module的變量。函數py::module::def()生成綁定代碼,将add()函數暴露給Python。

我們使用CMake進行編譯。首先寫一個CMakeLists.txt。

cmake_minimum_required(VERSION 2.8.12)
project(example)

add_subdirectory(pybind11)
pybind11_add_module(example example.cpp)      

就是CMakeList.txt和example.cpp放在一個目錄下面。

cmake .
make      

會生成example.cpython-36m-x86_64-linux-gnu.so檔案。

這個檔案就是python可以調用的檔案。還是在相同目錄下運作python,進入python指令行

import example
example.add(3, 4)
[out]: 7      

3. STL和python内建資料類型的對應關系

在使用python程式設計時,常使用内建容器作為函數的參數和傳回值,python語言的這種特性使我們的程式變得非常靈活和易于了解。那麼在使用pybind11封裝C++實作的函數的時候,如何保留這一特性呢?本文介紹pybind11實作list和dict作為參數及傳回值的方法。

混合程式設計:如何用python11調用C++

傳回vector

//檔案名:func.cpp  
#include "func.h"  
 
vector<long> list_square(vector<long> &in_list, vector<long>& out_list){  
    vector<long>::iterator iter;  
    for(iter = in_list.begin(); iter != in_list.end(); iter++){  
        out_list.push_back(*iter * *iter);  
    }  
    return out_list;  
}  
 
map<string, long> dict_square(map<string, long>& in_dict, map<string, long>& out_dict){  
    map<string, long>::iterator iter;  
    iter = in_dict.begin();  
    while(iter != in_dict.end()){  
        out_dict.insert({iter->first, iter->second * iter->second});  
        iter++;  
    }  
    return out_dict;  
}      
  • 寫pybind11封裝函數
//檔案名:func_wrapper.cpp  
#include <pybind11/pybind11.h>  
#include<pybind11/stl.h>  
#include "func.h"  
 
PYBIND11_MODULE(square, m){  
    m.doc() = "Square the members of the container";  
    m.def("list_square", &list_square);  
    m.def("dict_square", &dict_square);  
}      

傳回struct

#include <pybind11/pybind11.h>
#include <iostream>
struct Foo {
    std::string a;
};

void show(Foo f) {
    std::cout << f.a << std::endl;
}

namespace py = pybind11;

PYBIND11_PLUGIN(example) {
    py::module m("example", "pybind11 example plugin");

    m.def("show", &show, "Prints a");
    py::class_<Foo>(m, "Foo")
    .def_readwrite("a",    &Foo::a);

    return m.ptr();
}      
import sys
sys.path.append(".")
import example

b = example.Foo
b.a = "Hello"
example.show(b)      

此外:提供一些常用的參考連結

pybind11 — Seamless operability between C++11 and Python

python調用C++之pybind11入門

python調用c++利器–pybind11

基于pybind11實作Python調用c++編寫的CV算法–下 (Linux+Cmake)

跟我一起學習pybind11 之一

Passing by value #161

pybind11封裝的函數實作内建容器作為參數及傳回值

本文分享自華為雲社群《混合程式設計 — python調用C++之pybind11入門》,原文作者:SNHer。

點選關注,第一時間了解華為雲新鮮技術~

繼續閱讀