溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

python怎么創(chuàng)建生成動(dòng)態(tài)鏈接庫dll

發(fā)布時(shí)間:2020-07-28 12:06:49 來源:億速云 閱讀:356 作者:小豬 欄目:開發(fā)技術(shù)

小編這次要給大家分享的是python怎么創(chuàng)建生成動(dòng)態(tài)鏈接庫dll,文章內(nèi)容豐富,感興趣的小伙伴可以來了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。

如今,隨著深度學(xué)習(xí)的發(fā)展,python已經(jīng)成為了深度學(xué)習(xí)研究中第一語言。絕大部分的深度學(xué)習(xí)工具包都有python的版本,很多重要算法都有python版本的實(shí)現(xiàn)。為了將這些算法應(yīng)用到具體工程中,這些工具包也提供了不同類型的接口。

動(dòng)態(tài)鏈接庫(.dll,.so)是系統(tǒng)開發(fā)中一種非常重要的跨語言協(xié)作方式。把python語言寫成的算法編譯成動(dòng)態(tài)庫,能夠提供給其他語言調(diào)用,這能夠在很大程度上提高算法的開發(fā)效率。

但是,雖然python可以調(diào)用其他語言生成的動(dòng)態(tài)庫,python作為一種腳本語言,本身是不能直接編譯生成動(dòng)態(tài)庫的。為了生成動(dòng)態(tài)庫,我們借助cython,將python腳本變成c語言文件。具體過程,我們通過一個(gè)簡(jiǎn)單的例子來解釋。

def str_add(str1,str2): 
    return int(str1) + int(str2)

  這個(gè)代碼,將兩個(gè)數(shù)字組成的字符串轉(zhuǎn)化成數(shù)字,并求和。我們把這個(gè)代碼保存成run.py備用。根據(jù)cython的語法,我們給出cython版本的函數(shù):

cdef public str_add(str1,str2):
     return int(str1) + int(str2)

  和前面python版本的相比,cdef替換了def,并加了public關(guān)鍵字,表示這個(gè)函數(shù)要導(dǎo)出。將這個(gè)代碼保存成pyx文件,比如run.pyx。

接下來,我們執(zhí)行如下命令,把這個(gè)代碼變成c語言版本:

cython run.pyx

這時(shí),目錄下面生出來run.h和run.c兩個(gè)文件。這個(gè)兩個(gè)文件通過調(diào)用python的C-API實(shí)現(xiàn)了run.py代碼的功能。

接下來,我們編寫動(dòng)態(tài)庫的主文件dllmain.c:

#include <Python.h>
#include <Windows.h>
#include "run.h"
 
extern __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b) {
  return PyLong_AsLong(str_add(PyUnicode_FromString(a),PyUnicode_FromString(b)));<br data-filtered="filtered">
}
 
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved) {
  switch( fdwReason ) {
    case DLL_PROCESS_ATTACH:
      Py_Initialize();
      PyInit_run(); #dll初始化的時(shí)候調(diào)用,這是python3的寫法,python2改成,initrun()。參見生成的run.h
      break;
    case DLL_PROCESS_DETACH:
      Py_Finalize();
      break;
  }
  return TRUE;
}

  該文件定義了導(dǎo)出函數(shù)_str_add。在python中,所有數(shù)據(jù)都以pyobject進(jìn)行存儲(chǔ)。這個(gè)函數(shù)通過PyUnicode_FromString,將兩個(gè)字符串變成python對(duì)象類型,并調(diào)用run.h里面的函數(shù)str_add求和,并把結(jié)果通過PyLong_AsLong函數(shù)從python對(duì)象,變成整形數(shù)字。

我們可以通過如下命令,將這個(gè)代碼編譯生成dll:

cl /LD dllmain.c run.c -IC:\python36\include C:\python36\libs\python36.lib

這里python的路徑,根據(jù)不同電腦python的安裝位置,做相應(yīng)調(diào)整。

生成的dll,我們寫個(gè)簡(jiǎn)單調(diào)用,測(cè)試一下:

#include "stdio.h"
#include "stdlib.h"
extern __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b);
 
#pragma comment(lib,"dllmain.lib")
 
int main()
{
 printf("%d \n", _str_add("123","456"));
 return 0;
}

  輸出結(jié)果: 579,正好等于123+456。

通過以上步驟,我們已經(jīng)能夠把python代碼實(shí)現(xiàn)的功能,封裝成動(dòng)態(tài)庫。然而,這個(gè)動(dòng)態(tài)庫無法在沒有安裝python的機(jī)器上面運(yùn)行。事實(shí)上,python代碼,通常需要很多依賴包才能運(yùn)行。而且,每段代碼需要的依賴包是不一樣的。為了查找這些包,我們采用另外一個(gè)工具pyinstaller。具體步驟簡(jiǎn)介如下:

virtualenv envpack # 創(chuàng)建新的環(huán)境,python包依賴比較復(fù)雜,創(chuàng)建新環(huán)境可以減少最終引入的包
cd envpack # 進(jìn)入目錄
#復(fù)制run.py到這個(gè)目錄,run.py運(yùn)行需要的包,和最終dll需要的包是一樣的
Scripts\activate # 激活并切換到virtualenv環(huán)境
pip install pyinstaller # 安裝打包工具pyinstaller
pip install numpy # 安裝numpy等腳本需要的庫,查看你的import
pyinstaller run.py # 打包命令
Scripts\deactivate # 打包成功后,使用命令取消激活環(huán)境
需要打包的文件在envpack\dist, 包括很多.dll和.pyd文件,把這些文件和dll一起發(fā)布即可。

看完這篇關(guān)于python怎么創(chuàng)建生成動(dòng)態(tài)鏈接庫dll的文章,如果覺得文章內(nèi)容寫得不錯(cuò)的話,可以把它分享出去給更多人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI