[英]communicate between python and C++
我想創建一個python模塊,它可以從C ++類調用它的函數,並從該類調用c ++函數
我看過boost然而它似乎沒有任何意義它指的是一個共享庫(我不知道如何創建)並且我不能放棄他們在示例中使用的代碼(這看起來很混亂)
這是他們的hello world教程( http://www.boost.org/doc/libs/1_55_0b1/libs/python/doc/tutorial/doc/html/index.html#python.quickstart )
遵循C / C ++傳統,讓我們從“你好,世界”開始吧。 一個C ++函數:
char const* greet()
{
return "hello, world";
}
可以通過編寫Boost.Python包裝器來暴露給Python:
include <boost/python.hpp>
BOOST_PYTHON_MODULE(hello_ext)
{
using namespace boost::python;
def("greet", greet);
}
而已。 我們完成了。 我們現在可以將其構建為共享庫。 現在可以看到生成的DLL。 這是一個Python會話示例:
>>> import hello_ext
>>> print hello_ext.greet()
hello, world
下一站...從頭到尾構建Hello World模塊......
有人可以幫助解釋正在做什么,最重要的是python如何知道C ++文件
Python不了解C ++文件,它只會知道從C ++文件編譯的擴展模塊 。 此擴展模塊是一個目標文件,稱為共享庫。 這個文件有一個接口,它看起來像Python 是一個普通的Python模塊 。
只有在告訴編譯器編譯C ++文件並將其與所需的所有庫鏈接之后,才會存在此目標文件。 當然,所需的第一個庫是Boost.Python本身,它必須在您編譯的系統上可用。
您可以告訴Python為您編譯C ++文件,這樣您就不需要亂用編譯器及其庫標志。 為此,您需要一個名為setup.py
的文件,您可以使用Setuptools庫或標准Distutils來定義如何在系統上安裝其他Python模塊。 安裝的其中一個步驟是編譯所有擴展模塊,稱為build_ext
階段。
讓我們假設您有以下目錄和文件:
hello-world/
├── hello_ext.cpp
└── setup.py
setup.py
的內容是:
from distutils.core import setup
from distutils.extension import Extension
hello_ext = Extension(
'hello_ext',
sources=['hello_ext.cpp'],
include_dirs=['/opt/local/include'],
libraries=['boost_python-mt'],
library_dirs=['/opt/local/lib'])
setup(
name='hello-world',
version='0.1',
ext_modules=[hello_ext])
正如您所看到的,我們告訴Python我們要編譯一個擴展,源文件在哪里,以及要找到包含的庫。 這取決於系統 。 此處顯示的示例適用於Mac OS X系統,其中Boost庫是通過MacPorts安裝的。
hello_ext.cpp
的內容如教程所示,但要注意重新排序,以便BOOST_PYTHON_MODULE
宏出現在必須導出到Python的定義之后 :
#include <boost/python.hpp>
char const* greet()
{
return "hello, world";
}
BOOST_PYTHON_MODULE(hello_ext)
{
using namespace boost::python;
def("greet", greet);
}
然后,您可以通過在命令行上執行以下命令告訴Python編譯和鏈接:
$ python setup.py build_ext --inplace
running build_ext
building 'hello_ext' extension
/usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/opt/local/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c hello_ext.cpp -o build/temp.macosx-10.9-x86_64-2.7/hello_ext.o
/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 build/temp.macosx-10.9-x86_64-2.7/hello_ext.o -L/opt/local/lib -lboost_python-mt -o ./hello_ext.so
( --inplace
標志告訴Python將編譯產品留在源文件旁邊。默認是將它們移動到build
目錄,以保持源目錄清潔。)
之后,您將在hello-world
目錄中找到一個名為hello_ext.dll
(或Unix上的hello_ext.so
)的新文件。 如果在該目錄中啟動Python解釋器,您將能夠導入模塊hello_ext
並使用函數greet
,如Boost教程中所示。
Python是一種解釋型語言。 這意味着它需要一個虛擬機來執行語句。 例如,如果它遇到a = 5
,python(或者更確切地說是解釋你的python代碼的虛擬機),將在內存中創建一個包含一些信息和值5的對象,並確保對a
任何后續引用都會找到物體。 對於像input
這樣的更復雜的語句也是如此,在這些命令上,虛擬機將觸發一個硬編碼的例程,它將在返回讀取下一段python代碼之前做很多工作。 到現在為止還挺好。
關於模塊。 發出import
語句時,python將在其路徑中查找指定的模塊名稱。 這通常是一個.py
文件,只包含要解釋的純Python代碼。 但這也可以是一個.pyd
文件,包含python可以使用的編譯例程,就像可執行文件可以使用共享庫一樣 。 此文件包含符號和入口點,以便在解釋器找到特殊方法名稱(如mymodule.mymethod()
它知道在何處查找要執行的例程並運行它。
但是,這些例程必須符合特定的接口,這就是為什么將C / C ++函數公開給python並不簡單。 最明顯的問題是python int
不是C int
,不是short
,甚至不是long
。 它是一個特殊的結構,它包含更多信息,例如引用變量的頻率(能夠為不再引用的變量釋放內存),它所擁有的值的類型等等。當然,典型的C / C ++庫不適用於這些復雜類型,但使用vanilla int
, float
, char*
和其他漂亮的普通類型。 因此,必須將必要的python值轉換為庫可以理解的簡單C類型,並將庫提供的潛在結果轉換為python虛擬機可用的格式。 這就是所謂的包裝器 。 包裝器還必須處理有趣的事情,如引用計數,堆上的內存管理,初始化和完成以及其他猴子。 查看一些示例 ,了解這些代碼的外觀。 這不是非常復雜,但仍然有些工作。
現在,當調用可笑的簡單def("greet", greet);
你會了解Python.Boost
庫(或其他重要的包裝工具)所做的所有艱苦工作def("greet", greet);
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.