簡體   English   中英

在python和C ++之間進行通信

[英]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 intfloatchar*和其他漂亮的普通類型。 因此,必須將必要的python值轉換為庫可以理解的簡單C類型,並將庫提供的潛在結果轉換為python虛擬機可用的格式。 這就是所謂的包裝器 包裝器還必須處理有趣的事情,如引用計數,堆上的內存管理,初始化和完成以及其他猴子。 查看一些示例 ,了解這些代碼的外觀。 這不是非常復雜,但仍然有些工作。

現在,當調用可笑的簡單def("greet", greet);你會了解Python.Boost庫(或其他重要的包裝工具)所做的所有艱苦工作def("greet", greet);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM