亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

在python中調用C/C++的三種方法

 更新時間:2024年02月02日 15:02:47   作者:哦豁灬  
這篇文章主要給大家介紹了關于在python中調用C/C++的三種方法,Python可以通過調用C/C++接口來實現(xiàn)與C/C++語言的交互,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

Python 是一種很好用的膠水語言,利用Python的簡潔和C++的高效,基本可以解決99%的問題了,剩下那 1% 的問題也就不是問題了,畢竟不是所有問題都可解。

一般的,Python和C++的交互分為這兩種情況:

  • 用C++擴展Python:當一個Python項目中出現(xiàn)了性能瓶頸時,將瓶頸部分抽離出來,用C++封裝成一個Python可以調用的模塊(so庫);
  • 將Python內嵌入C++:當一個C++項目中有部分功能預期將會經(jīng)常變更需求,期望獲得更高的靈活性時,將這部分功能用Python實現(xiàn),在C++中進行調用。

這里討論前者,在 python 中調用 C/C++ 代碼的方法很多,這里記錄三種方法的使用。

1 C/C++ 編譯成可執(zhí)行文件,python 通過 subprocess 調用

C/C++ 代碼正常編寫,然后編譯成 exe/elf 格式的可執(zhí)行文件,Python 利用 subprocess 調用該可執(zhí)行文件即可。好處是改動小,不好是至少需要兩個進程跑代碼,而且 C/C++ 和 Python 通訊比較麻煩。

這種方法簡單粗暴,不太好用,沒什么好說的。

2 ctypes

C/C++ 在編寫代碼的時候略微改動,然后編譯成 dll/so 格式的動態(tài)庫文件,Python 利用 ctypes 調用該庫文件即可。好處一個進程內運行,C/C++ 側改動小,壞處是 Python 側需適配代碼比較多。

ctypes 是 python 自帶的一個庫,可以用來調用 c/cpp 的動態(tài)鏈接庫。使用 ctypes 調用 c++ 代碼步驟如下:

  • 編寫 cpp 代碼,將其編譯成動態(tài)鏈接庫(.so 或者 .dll 文件)。
  • 在 python 代碼文件中導入 ctypes 庫,并使用 ctypes.cdll.LoadLibrary() 方法加載動態(tài)鏈接庫。
  • 使用 ctypes 定義 c++ 函數(shù)的參數(shù)類型和返回值類型,并調用 c++ 函數(shù)。

2.1 編譯 C++

一個簡單的 demo:

dll.cpp

extern "C" int add(int a, int b) {
	return a + b;
}

在目錄 python_call_c_cpp 下,使用 g++ 編譯 dll.cpp

g++ --shared -fPIC dll.cpp -o libadd.so

編譯完成后,在目錄下會生成一個 libadd.so 文件:

2.2 python 調用 C/C++ 庫

main.py

import ctypes

# 加載動態(tài)鏈接庫 
lib = ctypes.cdll.LoadLibrary("./libadd.so") 
# 定義函數(shù)參數(shù)類型和返回值類型 
lib.add.argtypes = [ctypes.c_int, ctypes.c_int] 
lib.add.restype = ctypes.c_int 

# 調用 C++ 函數(shù) 
result = lib.add(1, 2) 
print("調用C++庫的結果:" + str(result))

執(zhí)行 python3 main.py:

3 Boost.Python

Boost作為一個大寶庫,提供了我們所需要的這一功能。并且,在Boost的許多庫中,已經(jīng)默認使用了Boost.Python,所以也算是經(jīng)過了充分的測試。

3.1 安裝

Boost的大部分功能都是以頭文件的形式提供的,無需安裝;但是也有少部分功能,需要進行手動編譯。Boost.Python 需要進行手動編譯。

3.2 一個簡單的 demo

用C++實現(xiàn)一個模塊,在Python中調用時,可以返回一個特定的字符串。

#include <boost/python.hpp>

char const* greet()
{
	return "hello, boost";
}

BOOST_PYTHON_MODULE(hello_boostpy)
{
	using namespace boost::python;
	def("greet", greet);
}

將其編譯成動態(tài)鏈接庫的形式:

g++ -I /usr/include/python2.7/ -fPIC -shared -o hello_boostpy.so http://hello_boostpy.cc -lboost_python

這時可以使用ldd看看hello_boostpy.so可不可以找到libboost_python,找不到的話,需要手動將其路徑加入環(huán)境變量LD_LIBRARY_PATH中,或者用ldconfig相關的命令也可以。

在Python中使用hello_boostpy庫:

# -*- coding: utf-8 -*-
import sys
sys.path.append('.')

def test():
    import hello_boostpy
    return hello_boostpy.greet()

if __name__ == "__main__":
    print test()

接下來,我們在C++實現(xiàn)的模塊中,添加一個類,并且嘗試向C++方向傳入Python的list類型對象。

C++ 類:

#include <boost/python.hpp>
#include <vector>
#include <string>
#include <sstream>
using namespace boost::python;

struct Person
{
	void set_name(std::string name) { this->name = name; }
	std::string print_info();
	void set_items(list& prices, list& discounts);
	
	
	std::string name;
	std::vector<double> item_prices;
	std::vector<double> item_discounts;
};

其中,Python方的list類型,在Boost.Python中有一個對應的實現(xiàn)boost::python::list(相應的,dict、tuple等類型都有對應實現(xiàn))。在set_items中,我們將會用boost::python::extract對數(shù)據(jù)類型做一個轉換。

void Person::set_items(list& prices, list& discounts)
{
	for(int i = 0; i < len(prices); ++i)
	{
		double price = extract<double>(prices[i]);
		double discount = extract<double>(discounts[i]);
		item_prices.push_back(price);
		item_discounts.push_back(discount);
	}
}

Python模塊定義部分依舊是非常直觀的代碼:

BOOST_PYTHON_MODULE(person)
{
	class_<Person>("Person")
		.def("set_name", &Person::set_name)
		.def("print_info", &Person::print_info)
		.def("set_items", &Person::set_items)
	;	
}

在Python代碼中,就可以像使用一個Python定義的類一樣使用Person類了:

# -*- coding: utf-8 -*-
import sys
sys.path.append('.')

def test():
    import person
    p = person.Person()
    p.set_name('Qie')
    p.set_items([100, 123.456, 888.8], [0.3, 0.1, 0.5])
    print p.print_info()

if __name__ == "__main__":
    test()

附c++調用Python:

將Python安裝目錄下的include和libs文件夾引入到項目中

將libs目錄下的python37.lib復制一份為python37_d.lib

1、Python腳本

def Hello():
    print("Hello")
     
def Add(a,b):
    return  a+b

2、C++調用python腳本

#include <Python.h>
using namespace std;
 
int main()
{
    Py_Initialize();              //初始化,創(chuàng)建一個Python虛擬環(huán)境
    if (Py_IsInitialized())
    {
        PyObject* pModule = NULL;
        PyObject* pFunc = NULL;
        pModule = PyImport_ImportModule("test_python");  //參數(shù)為Python腳本的文件名
        if (pModule)
        {
            pFunc = PyObject_GetAttrString(pModule, "Hello");   //獲取函數(shù)
            PyEval_CallObject(pFunc, NULL);           //執(zhí)行函數(shù)
        }
        else
        {
            printf("導入Python模塊失敗...\n");
        }
    }
    else
    {
        printf("Python環(huán)境初始化失敗...\n");
    }
    Py_Finalize();
}

接口方法

Python3.6提供給C/C++接口函數(shù),基本都是定義pylifecycle.h,pythonrun.h,ceval.h中。

  • Py_Initialize() 和 Py_Finalize()
    必須先調用Py_Initialize()進行初始化,這個API用來分配Python解釋器使用的全局資源,應用程序結束時需要調用Py_Finalize()來關閉Python的使用環(huán)境。
  • Py_IsInitialized()
    用來判斷Python解釋器是否初始化成功,true為成功,false為失敗。
  • PyErr_Print() & PyErr_Clear()
    執(zhí)行Python出錯時,PyErr_Print()可將錯誤信息顯示出來,PyErr_Clear()將錯誤信息在Python解釋器的緩存清除。
  • PyRun_SimpleString()
    這個函數(shù)能夠用來執(zhí)行簡單的Python語句。
  • PyEval_InitThreads()
    如果使用多線程調用Python腳本,就需要在初始化Python解釋器時調用PyEval_InitThreads()來啟用線程支持(導致Python內部啟用線程鎖),最好在主線程啟動時就調用。該API同時也鎖定全局解釋鎖,所以,還需要在初始化完成后需要自行釋放鎖。
    如果不需要使用多線程,不建議啟用該選項,互斥鎖也會不可避免的增加系統(tǒng)開銷。

3、規(guī)范化語法

#include<Python.h> //添加python的聲明
 
using namespace std;
 
int main()
{
Py_Initialize(); //1、初始化python接口
 
//初始化使用的變量
PyObject* pModule = NULL;
PyObject* pFunc = NULL;
PyObject* pName = NULL;
 
//2、初始化python系統(tǒng)文件路徑,保證可以訪問到 .py文件
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
 
//3、調用python文件名。當前的測試python文件名是test.py。在使用這個函數(shù)的時候,只需要寫文件的名稱就可以了。不用寫后綴。
pModule = PyImport_ImportModule("test");
 
//4、調用函數(shù)
pFunc = PyObject_GetAttrString(pModule, "AdditionFc");
 
//5、給python傳參數(shù)
PyObject* pArgs = PyTuple_New(2);//函數(shù)調用的參數(shù)傳遞均是以元組的形式打包的,2表示參數(shù)個數(shù)。如果AdditionFc中只有一個參數(shù)時,寫1就可以了。這里只先介紹函數(shù)必須有參數(shù)存在的情況。
 
 
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 2)); //0:表示序號。第一個參數(shù)。
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 4)); //1:也表示序號。第二個參數(shù)。i:表示傳入的參數(shù)類型是int類型。
 
//6、使用C++的python接口調用該函數(shù)
PyObject* pReturn = PyEval_CallObject(pFunc, pArgs);
 
//7、接收python計算好的返回值
int nResult;
PyArg_Parse(pReturn, "i", &nResult);//i表示轉換成int型變量。在這里,最需要注意的是:PyArg_Parse的最后一個參數(shù),必須加上“&”符號。
 
//8、結束python接口初始化
Py_Finalize();
}

總結 

到此這篇關于在python中調用C/C++的三種方法的文章就介紹到這了,更多相關python調用C/C++內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • pytorch自定義初始化權重的方法

    pytorch自定義初始化權重的方法

    今天小編就為大家分享一篇pytorch自定義初始化權重的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • Python requests庫參數(shù)提交的注意事項總結

    Python requests庫參數(shù)提交的注意事項總結

    這篇文章主要給大家介紹了關于Python requests庫參數(shù)提交的注意事項,文中通過示例代碼和圖片介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • Python matplotlib生成圖片背景透明的示例代碼

    Python matplotlib生成圖片背景透明的示例代碼

    這篇文章主要介紹了Python matplotlib生成圖片背景透明的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • 利用python+ffmpeg合并B站視頻及格式轉換的實例代碼

    利用python+ffmpeg合并B站視頻及格式轉換的實例代碼

    這篇文章主要介紹了利用python+ffmpeg合并B站視頻及格式轉換的實例代碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Python3.5局部變量與全局變量作用域實例分析

    Python3.5局部變量與全局變量作用域實例分析

    這篇文章主要介紹了Python3.5局部變量與全局變量作用域,結合實例形式分析了Python3.5局部變量與全局變量的定義、作用域及相關操作注意事項,需要的朋友可以參考下
    2019-04-04
  • Python的Flask框架應用調用Redis隊列數(shù)據(jù)的方法

    Python的Flask框架應用調用Redis隊列數(shù)據(jù)的方法

    這里為大家?guī)鞵ython的Flask框架應用調用Redis隊列數(shù)據(jù)的方法,從而能夠實現(xiàn)異步無阻塞從而提高某些實時處理情況下程序的性能,需要的朋友可以參考下
    2016-06-06
  • 基于python3實現(xiàn)socket文件傳輸和校驗

    基于python3實現(xiàn)socket文件傳輸和校驗

    這篇文章主要為大家詳細介紹了基于python3實現(xiàn)socket文件傳輸和校驗,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • django項目中使用手機號登錄的實例代碼

    django項目中使用手機號登錄的實例代碼

    這篇文章主要介紹了django項目中使用手機號登錄的實例代碼,非常不錯,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-08-08
  • Python Django ORM與模型詳解

    Python Django ORM與模型詳解

    這篇文章主要介紹了django的ORM與模型的實現(xiàn)原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧v
    2021-11-11
  • python密碼學黑客攻擊RSA密碼

    python密碼學黑客攻擊RSA密碼

    這篇文章主要為大家介紹了python密碼學黑客攻擊RSA密碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05

最新評論