【问题标题】:Calling Python function from Go and getting the function return value从 Go 调用 Python 函数并获取函数返回值
【发布时间】:2013-10-24 05:55:36
【问题描述】:

我正在编写一个Go 程序。从这个 Go 程序中,我想调用另一个文件中定义的 Python 函数并接收该函数的返回值,以便我可以在 Go 程序的后续处理中使用它。不过,我无法在我的 Go 程序中获取任何返回的数据。以下是我认为可行但显然行不通的最小示例:

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

如果我打电话给go run gofile,我会得到以下输出:

here we go...
command args: [python -c 'import pythonfile; print pythonfile.cat_strings("foo", "bar")']
concatentation length:  0
concatenation:  
...done

几点说明:

  • 我在 Python 调用中使用了-c 标志,因此我可以直接调用函数cat_strings。假设 cat_strings 是一个 Python 文件的一部分,其中包含其他 Python 程序使用的实用函数,因此我没有任何 if __name__ == __main__ 业务。
  • 我不想将Python文件修改为print a + b(而不是return a + b);请参阅前面的观点,该函数是一组实用函数的一部分,应该可由其他 Python 代码调用。
  • cat_strings 函数是虚构的,用于演示目的;真正的功能是我不想简单地在 Go 中重新实现的东西。我对如何从 Go 调用 Python 函数并获取返回值非常感兴趣。

【问题讨论】:

  • 我感觉使用os/exec 不容易做到这一点。所有os/exec 函数仅返回标准输出和/或标准错误。
  • @Intermernet 我以为我在python -c 'import pythonfile; print pythonfile.cat_strings("foo", "bar")' 中对print 的调用会打印到标准输出。
  • 当您从命令提示符运行python -c 'import pythonfile; print pythonfile.cat_strings("foo", "bar")' 时是否打印?如果它输出到标准输出(或标准错误),那么它应该从 os/exec 工作。
  • @Intermernet 是的,这就是为什么我觉得奇怪的是 Go 似乎没有收到结果

标签: python go


【解决方案1】:

通过简单地删除命令本身的引号,我设法获得了一些工作代码:

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

果然,在source,你有这个功能(至少对于Windows,我不知道它是否适用于其他操作系统):

// 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 { ...

所以您的代码最终会通过以下命令行调用:

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

如果经过测试,它会评估为一个字符串并且不返回任何内容,因此输出长度为 0。

【讨论】:

  • 刚刚在 Linux (Ubuntu) 上测试并删除单引号的作品,所以似乎是一个跨平台的解决方案。
  • 不错!乐意效劳。尽管正如其他人建议的那样,如果您要大量使用它,最好使用 CPython API 绑定或使用网络接口在 Python 和 Go 之间进行通信。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-24
  • 2014-05-28
  • 1970-01-01
  • 2018-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多