初探pybind11——Python調(diào)用C++函數(shù)

本文使用Anaconda環(huán)境進行演示,python版本為3.8,若讀者不使用Anaconda,需自行配置環(huán)境。

Pybind11是一個純頭文件庫,用于將C++函數(shù)封裝出Python接口。該庫可以很方便地使用conda進行安裝,執(zhí)行命令conda install pybind11 pytest淤翔。完成安裝后,我們開始編寫第一個程序佩谷,命名為hello.cpp旁壮。

// hello.cpp
#include <pybind11/pybind11.h>
#include <iostream>
namespace py = pybind11;
using namespace std;

void say_hello(const char* name)
{
    cout << "Hello, " << name << "! This is a message from C++ library!" << endl;
}

PYBIND11_MODULE(hello, m)
{
    m.def("say_hello", &say_hello, "Print hello to the name.");
}

上面的cpp文件中,say_hello為程序函數(shù)谐檀,PYBIND11_MODULE為包裝函數(shù)抡谐,此二者在實際應(yīng)用中一般會分別存放在不同的文件中,但在本例中為演示需要桐猬,我將他們放在了同一個文件中麦撵。

PYBIND11_MODULE是一個宏定義,其功能是創(chuàng)建一個函數(shù)溃肪,這個函數(shù)會在Python執(zhí)行import語句時被調(diào)用免胃,其接受兩個參數(shù),第一個參數(shù)為模塊名稱惫撰,這里我們直接將hello填入羔沙,稍候可以在Python中使用import hello導(dǎo)入該模塊;第二個參數(shù)m是創(chuàng)建Python關(guān)聯(lián)代碼的主接口厨钻,其類型為py::module_扼雏。module_::def()用于生成能夠?qū)?code>say_hello函數(shù)暴露給Python的代碼坚嗜,其第一個參數(shù)為字符串,將會成為Python中調(diào)用的函數(shù)名诗充;第二個參數(shù)是C++函數(shù)的引用苍蔬;第三個參數(shù)是說明字符串,在Python中可以使用help(say_hello)查看蝴蜓。

現(xiàn)在碟绑,我們可以著手編譯這個庫了,這里我使用g++進行編譯励翼,通過-shared參數(shù)將其編譯為共享庫,在Linux和MacOS上的編譯命令稍有不同:

  • Linux
g++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) hello.cpp -o hello$(python3-config --extension-suffix)
  • MacOS
g++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) hello.cpp -o hello$(python3-config --extension-suffix) -undefined dynamic_lookup

在我的系統(tǒng)中辜荠,會生成一個名為hello.cpython-38-darwin.so的文件汽抚,這就是編譯產(chǎn)生的共享庫文件。現(xiàn)在伯病,在當(dāng)前目錄進入python解釋器造烁,即可導(dǎo)入包并運行函數(shù):

$ python
Python 3.8.12 (default, Oct 12 2021, 06:23:56) 
[Clang 10.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import hello
>>> hello.say_hello("Tom")
Hello, Tom! This is a message from C++ library!

除了手動編譯外,還可以使用cmake工具進行跨平臺編譯配置午笛,在當(dāng)前目錄下新建一個CMakeLists.txt文件惭蟋,然后寫入下面的命令:

cmake_minimum_required(VERSION 3.4...3.18)
project(hello)
find_package(Python COMPONENTS Interpreter Development REQUIRED)
find_package(pybind11 REQUIRED)
pybind11_add_module(hello hello.cpp)

其中,find_package函數(shù)會自動找到正確的依賴包药磺,pybind11_add_module函數(shù)添加了一個名為hello的模塊告组。

保存退出后,執(zhí)行cmake . && make命令癌佩,即可看到編譯產(chǎn)生的共享庫文件木缝。


使用py::arg參數(shù)可以將變量名也暴露給python,同時围辙,若有需要我碟,還可以設(shè)置參數(shù)默認值:

PYBIND11_MODULE(hello, m)
{
    m.def("say_hello", &say_hello, "Print hello to the name.", py::arg("name")="Jack");
}

Python運行效果:

>>> import hello
>>> hello.say_hello()
Hello, Jack! This is a message from C++ library!
>>> hello.say_hello("Nic")
Hello, Nic! This is a message from C++ library!
>>> hello.say_hello(name="George")
Hello, George! This is a message from C++ library!
>>> help(hello.say_hello)
Help on built-in function say_hello in module hello:

say_hello(...) method of builtins.PyCapsule instance
    say_hello(name: str = 'Jack') -> None
    
    Print hello to the name.
(END)

py::arg參數(shù)還有一種簡化寫法,通過引入名稱空間pybind11::literals姚建,可以使用_a后綴來替代py::arg矫俺,例如,上面的一條m.def函數(shù)可以寫成:

using namespace pybind11::literals;
PYBIND11_MODULE(hello, m)
{
    m.def("say_hello", &say_hello, "name"_a="Jack");
}

除了包裝函數(shù)外掸冤,通過使用module_::attr函數(shù)可以將C++中的變量暴露給Python厘托,例如下面的C++程序:

// hello.cpp
#include <pybind11/pybind11.h>
#include <iostream>
namespace py = pybind11;
using namespace std;
using namespace pybind11::literals;

const char* where = "This is a message from C++ library!";
const char* cst = "This is an auto cast string by pybind11.";

void say_hello(const char* name)
{
    cout << "Hello, " << name << "!" << endl;
}

PYBIND11_MODULE(hello, m)
{
    m.def("say_hello", &say_hello, "name"_a="Jack");
    m.attr("where") = where;
    m.attr("cast") = py::cast(cst);
}

Python中運行效果:

>>> import hello
>>> hello.say_hello("Tom")
Hello, Tom!
>>> print(hello.where)
This is a message from C++ library!
>>> print(hello.cast)
This is an auto cast string by pybind11.
>>> type(hello.cast)
<class 'str'>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市稿湿,隨后出現(xiàn)的幾起案子催烘,更是在濱河造成了極大的恐慌,老刑警劉巖缎罢,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伊群,死亡現(xiàn)場離奇詭異考杉,居然都是意外死亡,警方通過查閱死者的電腦和手機舰始,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門崇棠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人丸卷,你說我怎么就攤上這事枕稀。” “怎么了谜嫉?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵萎坷,是天一觀的道長。 經(jīng)常有香客問我沐兰,道長哆档,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任住闯,我火速辦了婚禮瓜浸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘比原。我一直安慰自己插佛,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布量窘。 她就那樣靜靜地躺著雇寇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚌铜。 梳的紋絲不亂的頭發(fā)上谢床,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音厘线,去河邊找鬼识腿。 笑死,一個胖子當(dāng)著我的面吹牛造壮,可吹牛的內(nèi)容都是我干的渡讼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耳璧,長吁一口氣:“原來是場噩夢啊……” “哼成箫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起旨枯,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蹬昌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后攀隔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體皂贩,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡栖榨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了明刷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婴栽。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辈末,靈堂內(nèi)的尸體忽然破棺而出愚争,到底是詐尸還是另有隱情,我是刑警寧澤挤聘,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布轰枝,位于F島的核電站,受9級特大地震影響组去,放射性物質(zhì)發(fā)生泄漏鞍陨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一添怔、第九天 我趴在偏房一處隱蔽的房頂上張望湾戳。 院中可真熱鬧贤旷,春花似錦广料、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盅藻,卻和暖如春购桑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背氏淑。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工勃蜘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人假残。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓缭贡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辉懒。 傳聞我的和親對象是個殘疾皇子阳惹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容