http://blog.yuanzhaoyi.cn/2018/06/27/golang_python.html
python3-ctypes: https://docs.python.org/3.5/library/ctypes.html#ctypes.c_wchar_p
golang-cgo: https://golang.org/cmd/cgo/#hdr-Go_references_to_C
綜述
golang和python之間,當前可以通過golang的cgo和python的ctypes,把golang對象和python對象分別轉換為C對象,從而通過編譯和調用c的動態連接庫,完成交互。
python調用golang:
go 函數實現:
//libadd.go
package main
import "C"
//export add
func add(left, right int) int {
return left + right
}
func main() {
}
通過c-shared模式編譯成so:
go build -buildmode=c-shared -o libadd.so libadd.go
python調用so:
from ctypes import cdll
lib = cdll.LoadLibrary('./libadd.so')
print("Loaded go generated SO library")
result = lib.add(2, 3)
print(result)
注意
: 只有int可以不需要轉換,直接在go和C直接互相調用
對於不同的類型,需要使用cgo中定義的方法轉換,具體可以參考golang-cgo文檔。
比如string需要用C.char來傳遞,C.GoString(s)可以將C.char類型轉換為string,反之C.CString可以把string類型轉為 *C.char
使用舉例:
package main
import "C"
import (
"github.com/ppmoon/gbt2260"
"strings"
)
//export parsecode
func parsecode(s *C.char) (*C.char){
code := C.GoString(s)
region := gbt2260.NewGBT2260()
localCode := region.SearchGBT2260(code)
if len(localCode) < 3 {
return C.CString("沒有匹配上,,")
}
ret := strings.Join(localCode, ",")
return C.CString(ret)
}
//export add
func add(left, right int) int {
return left + right
}
func main() {
}
編譯.so:
go build -buildmode=c-shared -o ~/Develop/law_dev/law_service/util/parseareacode.so test_other.go
python調用:
用.argtype和.restype可以定義調用動態連接庫函數的傳入和傳出參數
# 通過golang的"github.com/ppmoon/gbt2260"包解析area code
import os
from ctypes import cdll, c_char_p
current_path = os.path.dirname(os.path.realpath(__file__))
lib = cdll.LoadLibrary(current_path + '/parseareacode.so')
parsecode = lib.parsecode
def get_list(area_code):
parsecode.argtype = c_char_p
parsecode.restype = c_char_p
result = lib.parsecode(area_code.encode("utf-8"))
return result.decode("utf-8").split(",")
簡單總結
Python與Go之間的參數傳遞, 處理非INT型時需要都轉為對應的C類型
ctypes需要顯式地聲明DLL函數的參數和返回期望的數據類型
注意在Python3中字符串bytes和string的區別
Go模塊需要//export 聲明外部可調用
Go處理C的類型是需要顯式轉換