LoginSignup
1
0

More than 1 year has passed since last update.

goで実装した関数をpythonから呼び出す

Posted at

やりたいこと

下図のようにGoで記述した関数をPythonから呼び出します。

まずはGoプログラムをビルドして共有ライブラリ(※)を作成し、ビルドした共有ライブラリをPythonから呼び出します。
※ Linuxだと共有ライブラリ.so、Windowsだとダイナミックライブラリ.dll

イメージ図.png

1. 共有ライブラリを作成

まずはGoでスクリプトを記述します。
記述する上でのポイントは以下です。

  • package名はmainにする
  • main関数を記述する
  • 特殊コメントのexportを記述する
test.go
// package名はmainにする
package main

import (
    "fmt"
    "C"
)

func main() {
    // main関数を記述
}

//export HelloWorld
func HelloWorld() {
    fmt.Println("Hello World")
}

//export AddNum
func AddNum (x1,x2 C.int) C.int {
    result := int(x1)+int(x2)
    return C.int(result)
}

//export AddStr
func AddStr (s1,s2 *C.char) *C.char {
    result := C.GoString(s1)+C.GoString(s2)
    return C.CString(result)
}

ここでインポートしている"C"パッケージですが、Goにはそのような名前のパッケージは存在しません。
C? Go? Cgo!の記事には以下のように記載されています。

C is a “pseudo-package”, a special name interpreted by cgo as a reference to C’s name space.

共有ライブラリの作成は以下のコマンドにより行います。
これによりtest.soという名前のファイルが作成されます。

ビルド
go build -buildmode=c-shared -o test.so test.go

共有ライブラリに記述した関数が含まれていることを確認します。
test.soのあるフォルダで以下のnmコマンドを実行します。

実行結果にAddNumなど、先ほど記述した関数の名前が含まれていることが確認できます。

[Go] $ nm test.so | grep " T "
00000000000ab480 T _AddNum
00000000000ab4e0 T _AddStr
00000000000ab440 T _HelloWorld
00000000000ab540 T __cgo_0e9602f8d2bc_Cfunc__Cmalloc
00000000000ab920 T __cgo_get_context_function
000000000006a4c0 T __cgo_panic
00000000000ab580 T __cgo_release_context
00000000000ab620 T __cgo_sys_thread_start
00000000000668c0 T __cgo_topofstack
00000000000ab790 T __cgo_try_pthread_create
00000000000ab830 T __cgo_wait_runtime_init_done
00000000000ab380 T __cgoexp_0e9602f8d2bc_AddNum
00000000000ab3e0 T __cgoexp_0e9602f8d2bc_AddStr
00000000000ab320 T __cgoexp_0e9602f8d2bc_HelloWorld
000000000006a520 T _crosscall2
00000000000aba30 T _crosscall_amd64
00000000000ab980 T _x_cgo_callers
00000000000ab5b0 T _x_cgo_init
00000000000ab8b0 T _x_cgo_notify_runtime_init_done
00000000000ab8f0 T _x_cgo_set_context_function
00000000000ab950 T _x_cgo_setenv
00000000000ab700 T _x_cgo_sys_thread_create
00000000000ab9e0 T _x_cgo_thread_start
00000000000ab970 T _x_cgo_unsetenv

2. Pythonから呼び出す

作成した共有ライブラリをPythonから使用するにはctypesモジュールを使用します。
引数を渡して結果を受け取るにはargtypesおよびrestypeでそれらの型を指定します。

実装例は以下のようになります。

test.py
from ctypes import *

# 共有ライブラリの読み込み
lib = cdll.LoadLibrary("test.so")

# HelloWorld関数を使用
f = lib.HelloWorld
f()

# AddNum関数を使用
f = lib.AddNum
f.argtypes = [c_int, c_int]
f.restype = c_int
result = f(1, 2)
print("AddNum :", result)

# lib.AddStr関数を使用
f = lib.AddStr
f.argtypes = [c_char_p, c_char_p]
f.restype = c_char_p
result = f(b"Hoge", b"Piyo")
print("AddStr :", result)

作成したpythonスクリプトを実行すると、以下の通りPython側で結果を受け取れていることが確認できます。

実行結果
[Go] $ python test.py
Hello World
AddNum : 3
AddStr : b'HogePiyo'

参考資料

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0