You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于GraalVM Polyglot的Scala与Python运算符重载问题

问题:GraalVM Polyglot中Scala对象无法在Python中使用+运算符

我在Scala应用中使用GraalVM的Polyglot特性执行Python代码,测试REPL中v.__add__(1)能正常返回结果:

>> v

evaluating v
evaluated got Value(7)

v.add(1)
evaluating v.add(1)
evaluated got Value(8)

但执行`v + 1`时会报错`TypeError: unsupported operand type(s) for +: 'foreign' and 'int'`,如何实现`v + 1`的正常执行?

---

# 解决方案

仅通过`@targetName("__add__")`标注Scala方法无法让GraalVM的Python自动识别运算符重载,需要让Scala对象实现GraalVM的`Proxy`接口,主动暴露Python期望的特殊方法协议。

### 修改后的Scala代码
```scala
import org.graalvm.polyglot.{Context, Source, Value}
import org.graalvm.polyglot.proxy.Proxy
import scala.annotation.targetName
import scala.util.control.NonFatal

case class Value(v: Int) extends Proxy {
  @targetName("__add__")
  def +(i: Int): Value = Value(v + i)

  // 实现Proxy接口,让Python能正确获取__add__方法
  override def getMember(key: String): AnyRef = {
    key match {
      case "__add__" => (args: Array[AnyRef]) => 
        args.head match {
          case num: Int => this + num
          case num: Value => Value(this.v + num.v)
          case _ => throw new IllegalArgumentException("Unsupported type for +")
        }
      case _ => super.getMember(key)
    }
  }

  override def hasMember(key: String): Boolean = {
    key == "__add__" || super.hasMember(key)
  }
}

class Python(context: Context, v: Value) {
  private val language = "python"

  context.getBindings(language).putMember("v", v)

  def eval(code: String): AnyRef = {
    try {
      val source = Source
        .newBuilder(language, code, "<shell>")
        .interactive(false)
        .buildLiteral()

      println(s"evaluating $code")
      val res = context.eval(source)
      println(s"evaluated got $res")
      res
    } catch {
      case NonFatal(e) =>
        println(s"error evaluating $code")
        e.printStackTrace()
        null
    }
  }
}

object Python {
  def main(args: Array[String]): Unit = {
    val context = Context
      .newBuilder("python")
      .allowAllAccess(true)
      .build()

    val python = new Python(context, Value(7))

    while (true) {
      val line = scala.io.StdIn.readLine(">>> ")
      python.eval(line)
    }
  }
}

关键说明

  • 让Value类实现Proxy接口后,Python在解析v + 1时会自动查找__add__方法,此时getMember会返回我们定义的加法逻辑;
  • 扩展了支持Value对象之间相加的场景,增强通用性;
  • hasMember方法明确告知Python__add__方法存在,确保运算符解析流程正常触发。

修改后执行v + 1即可正常得到Value(8)的结果。


内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 17:05:56