Calling Python function from Go and getting the function return value

go, python

Solution

I managed to have some working code for this by simply removing the quote around the command itself:

package main

import "fmt"
import "os/exec"

func main() {
    cmd := exec.Command("python",  "-c", "import pythonfile; print pythonfile.cat_strings('foo', 'bar')")
    fmt.Println(cmd.Args)
    out, err := cmd.CombinedOutput()
    if err != nil { fmt.Println(err); }
    fmt.Println(string(out))
}

And sure enough, in the source, you have this function (for Windows, at least, I don't know if that works for other OSes):

// EscapeArg rewrites command line argument s as prescribed
// in http://msdn.microsoft.com/en-us/library/ms880421.
// This function returns "" (2 double quotes) if s is empty.
// Alternatively, these transformations are done:
// - every back slash (\) is doubled, but only if immediately
//   followed by double quote (");
// - every double quote (") is escaped by back slash (\);
// - finally, s is wrapped with double quotes (arg -> "arg"),
//   but only if there is space or tab inside s.
func EscapeArg(s string) string { ...

So your code is ending up passing the following command line call:

$ python -c "'import pythonfile; print pythonfile.cat_strings(\\"foo\\", \\"bar\\")'"

Which, if tested, evaluates to a string and returns nothing, hence the 0-length output.

Problem

I am writing a Go program. From this Go program, I would like to call a Python function defined in another file and receive the function's return value so I can use it in subsequent processing in my Go program. I am having trouble getting any returned data back in my Go program though. Below is a minimum example of what I thought would work, but apparently doesn't: gofile.go ``` package main import "os/exec" import "fmt" func main() { fmt.Println("here we go...") program := "python" arg0 := "-c" arg1 := fmt.Sprintf("'import pythonfile; print pythonfile.cat_strings(\"%s\", \"%s\")'", "foo", "bar") cmd := exec.Command(program, arg0, arg1) fmt.Println("command args:", cmd.Args) out, err := cmd.CombinedOutput() if err != nil { fmt.Println("Concatenation failed with error:", err.Error()) return } fmt.Println("concatentation length: ", len(out)) fmt.Println("concatenation: ", string(out)) fmt.Println("...done") } ``` pythonfile.py ``` def cat_strings(a, b): return a + b ``` If I call `go run gofile` I get the following output: ``` here we go... command args: [python -c 'import pythonfile; print pythonfile.cat_strings("foo", "bar")'] concatentation length: 0 concatenation: ...done ``` A few notes: - I'm using the `-c` flag in the Python invocation so I can call the function `cat_strings` directly. Assume `cat_strings` is part of a Python file full of utility functions that are used by other Python programs, hence why I don't have any `if __name__ == __main__` business. - I don't want to modify the Python file to `print a + b` (instead of `return a + b`); see the prior point about the function being part of a set of utility functions that ought to be callable by other Python code. - The `cat_strings` function is fictional and for demonstration purposes; the real function is something I don't want to simply reimplement in Go. I really am interested in how I can call a Python function from Go and get the return value.

Original source

Related problems