如何利用Golang為Python編寫模組

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

前言

由於公司的Python項目中有關於支付簽名與驗簽的模組,是自定的一些內部邏輯,基於安全性考慮, 希望改用C/C++或者Go 來重構該部分模組,做到加解簽過程透明,上層代碼只需要關心結果. 由於最近開始了Golang的學習,就嘗試完成這部分工作,整個過程都是邊踩坑邊完成,下面以範例代碼來分享一下整個過程的思路.

記錄

Go裡面需要顯示的引入C模組, 讓編譯器支援產生動態連結程式庫, 並且在代碼中可以使用C語言的資料類型,這個至關重要. Calling Go code from Python code 摘取一個最簡單例子

//libadd.gopackage mainimport "C"//export addfunc add(left, right int) int {    return left + right}func main() {}
go build -buildmode=c-shared -o libadd.so libadd.go
from ctypes import cdlllib = cdll.LoadLibrary('./libadd.so')print("Loaded go generated SO library")result = lib.add(2, 3)print(result)

The cgo export command is documented in go doc cgo, section "C references to Go". Essentially, write //export FUNCNAME before the function definition

有這麼一段話, 需要顯式注釋//export add 把 add函數公開給C調用

本以為很簡單的就能用, 興緻滿滿地把例子改一下, 改為簡單的處理字串的時候, 卻發現跑不起來了.

//libadd.gopackage mainimport "C"//export addfunc add(left, right string) string {    return left + right}func main() {}
from ctypes import CDLLlib = CDLL('./libadd.so')print("Loaded go generated SO library")result = lib.add("Hello", "World")print(result)
  • 這時候運行是出錯的

    再次翻看資料發現這麼一句話:

The python code is really short and this is only passing an integer back and forth (more complex string and struct cases are much more challenging).

這說明處理字串的時候並不是簡單改成string類型就可以.這時候翻開了BUILDING PYTHON MODULES WITH GO 1.5 , 這時能找到的最全面的資料, 可惜裡面的過程都過於複雜, 整個思路是用Go去寫C code, 類似寫解譯器一樣, 去抽象出PyObject然後按照API標準來註冊、處理、返回.我僅是希望以動態連結程式庫 的方式來能調用就可以了.

我開始思考, 為何例子中使用int類型就可以, 我改成一個簡單的接收string 返回string 卻一直失敗. py是利用ctypes來跟so模組進行互動, 這裡存在一個代碼的翻譯過程 Py -> C -> Go, 我能想到的對於字串資料型別的處理不一樣原因引起(後面事實證明了我的猜想).那麼思考一下, Py中的字串傳遞到Go裡面去使用什麼類型來接收呢? 翻閱了大量資料, 所有答案在Python Doc 官網關於ctypes模組中有能找到.我們來看一下這圖:


001.png


這裡可以很清楚的看到Python3 ctypes中字串 bytesstring 是對應的兩種指標類型.同時提供了argtypesrestype 來顯式轉換動態連結程式庫中函數的參數和傳回型別.(參考StackOverFlow)

這時候按照思考的流程來修改代碼

//libadd.gopackage mainimport "C"//export addfunc add(left, right *C.char) *C.char {      // bytes對應ctypes的c_char_p類型,翻譯成C類型就是 char *指標      merge := C.GoString(left) + C.GoString(right)    return C.CString(merge)}func main() {}

重新編譯

go build -buildmode=c-shared -o libadd.so libadd.go

Python中引用

import ctypesadd = ctypes.CDLL('./libadd.so').add# 顯式聲明參數和返回的期望類型add.argtypes = [ctypes.c_char_p, ctypes.c_char_p]add.restype = ctypes.c_char_pleft = b"Hello"right = b"World"print(add(left, right))

正確輸出結果:

b"HelloWorld"

就這樣, 一個基本的模組就完成, 只要關注傳入參數和返回結果的資料類型處理, 我只需要豐富函數的處理邏輯,Go模組中函數內部實現對於Python是透明,只要參數正確即可.其中關於 cgo更多的資訊, 大家可以自行查閱Golang.org

總結

  1. Python與Go之間的參數傳遞, 處理非INT型時需要都轉為對應的C類型
  2. ctypes需要顯式地聲明DLL函數的參數和返回期望的資料類型
  3. 注意在Python3中字串bytes和string的區別
  4. Go模組需要//export 聲明外部可調用
  5. Go處理C的類型是需要顯式轉換
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.