从Scala调用Python脚本函数

0 投票
1 回答
6174 浏览
提问于 2025-06-18 04:04

尝试从Scala调用Python函数时出现了错误,但当直接从命令行执行相同的命令时却没有问题。

下面是简化后的代码片段:

greeting.py

import logging
import os


def greet(arg):
    print("hey " + arg)

StraightPyCall.scala

package git_log

object StraightPyCall {

  def main(args: Array[String]): Unit = {

    val commandWithNewLineInBeginning =
      """
        |python -c "import sys;sys.path.append('~/playground/octagon/bucket/pythonCheck'); from greeting import *; greet('John')"
        |""".stripMargin

    //new line stripped out from beginning and end
    val executableCommand = commandWithNewLineInBeginning.substring(1, commandWithNewLineInBeginning.length - 1)

    println("command is :-")
    println(executableCommand)

    import sys.process._

    s"$executableCommand".!!
  }
}

上面这个Scala程序的输出是:

command is :-
python -c "import sys;sys.path.append('~/playground/octagon/bucket/pythonCheck'); from greeting import *; greet('John')"

  File "<string>", line 1
    "import
          ^
SyntaxError: EOL while scanning string literal
Exception in thread "main" java.lang.RuntimeException: Nonzero exit value: 1
    at scala.sys.package$.error(package.scala:26)
    at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.slurp(ProcessBuilderImpl.scala:134)
    at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.$bang$bang(ProcessBuilderImpl.scala:104)
    at git_log.StraightPyCall$.main(StraightPyCall.scala:19)
    at git_log.StraightPyCall.main(StraightPyCall.scala)

当我尝试执行控制台上打印的命令时,它运行得非常顺利。

python -c "import sys;sys.path.append('~/playground/octagon/bucket/pythonCheck'); from greeting import *; greet('John')"

结果是:

嘿,约翰

注意:下面是ProcessBuilder的toString表示(在调试时从堆栈跟踪中复制的):

[python, -c, "import, sys;sys.path.append('/Users/mogli/jgit/code-conf/otherScripts/pythonScripts/CallRelativePyFromBash/pyscripts');, from, Greet, import, *;, greet_with_arg('John')"]

请建议一下,commandWithNewLineInBeginning需要做什么修改才能在Scala中正常工作。

相关问题:

  • 暂无相关问题
暂无标签

1 个回答

1

在命令行中,它能正常工作是因为外壳程序(shell)会在执行python命令之前,先解析和理解这个字符串。而在Scala代码中,ProcessBuilder试图在没有外壳程序帮助的情况下解析和理解这个字符串。

我们可以帮助进行解析。这样做应该可以。

Seq("python"
   ,"-c"
   ,"import sys;sys.path.append('~/playground/octagon/bucket/pythonCheck'); from greeting import *; greet('John')"
   ).!!

如果你真的必须从完整的字符串开始,那么也许可以在处理之前把它拆分开。

举个例子:如果你知道这个模式总是“cmnd -c string”,那么这样做可能有效。

commandWithNewLineInBeginning.replaceAll("\"","")
                             .split("((?=-c)|(?<=-c))")
                             .map(_.trim)
                             .toSeq.!!

撰写回答