Calling Go code from Python code

Inspired by the ruby version from @jondot

With the release of Go 1.5 you can now call Go as a shared library in other languages. That little tidbit escaped me the first time I went through the release notes but after having the above ruby article come through my twitter stream I decided I should see if I could quickly get a simple example working between Go and Python.

First you have to write a short go func you want to expose to your python code in a simple file. I wrote one in libadd.go. The comments are critical to include so the functions are exported.

//libadd.go
package main

import "C"

//export add
func add(left, right int) int {
	return left + right
}

func main() {
}

Then you’re going to want to use the new buildmode option in 1.5


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

Make sure you’ve upgraded to 1.5.1 while having completely removed any previous version or you’ll get this error

imports runtime: C source files not allowed when not using cgo or SWIG: atomic_amd64x.c defs.c float.c heapdump.c lfstack.c malloc.c mcache.c mcentral.c mem_linux.c mfixalloc.c mgc0.c mheap.c msize.c os_linux.c panic.c parfor.c proc.c runtime.c signal.c signal_amd64x.c signal_unix.c stack.c string.c sys_x86.c vdso_linux_amd64.c

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).


from ctypes import cdll
lib = cdll.LoadLibrary('./libadd.so')
print "Loaded go generated SO library"
result = lib.add(2, 3)
print result

The Ruby post includes a full demo project that shows what the go code would look like that would go fetch several URLs using channels and return results back that project is here and it would probably be worth doing a Python version at some point the illustrates how to do more complex struct and types (this was a very limited post).

Here is some further reading:

the design doc around how this is going to all work
python ctypes and cffi
cgo and how types interplay with the export/import go C package
ctypes documentation
cffi documentation

You may also like...

5 Responses

  1. Paul Fortin says:

    Perhaps a note to indicate that the “//export add” comment is important!!!

  2. Ross says:

    Added, thanks!

  3. Aldo says:

    Would be better if you post more examples, because I’m adding a factorial function with channel and goroutines inside it, I got error

    Traceback (most recent call last):
    File “add.py”, line 7, in
    resfib = lib.factorial(6)
    File “/usr/local/var/pyenv/versions/3.5.0/lib/python3.5/ctypes/__init__.py”, line 360, in __getattr__
    func = self.__getitem__(name)
    File “/usr/local/var/pyenv/versions/3.5.0/lib/python3.5/ctypes/__init__.py”, line 365, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
    AttributeError: dlsym(0x7fbd9ac1f6f0, factorial): symbol not found

  4. mrberner says:

    @Aldo, because if you want to export something from package, the name of function to export must begin with capital letter.

  5. mahir says:

    For those wondering how to work with strings, here is the solution:
    https://gist.github.com/helinwang/4f287a52efa4ab75424c01c65d77d939

Leave a Reply

Your email address will not be published. Required fields are marked *