如何从 Julia 程序调用 Python 函数?

问题描述 投票:0回答:2

我使用 numpy、pandas、scikit-learn 在 Python 中编写了一些代码。是否可以从 Julia 程序调用此 Python 代码?

python julia
2个回答
13
投票

[2025 年更新]

较新的软件包 PythonCall.jl 已成为 Julia 与 Python 接口的事实上的标准。我在我的书的第二版中广泛讨论了它的用法,但是您可以在上面的链接中找到它的良好文档,或者在这里获取书中使用的源代码(Julia/Python 接口位于第 1 章)。 7).

[/2025 年更新]

我认为你可以想到从 Julia 调用 Python 代码的三种不同方式,按照从最低级别到最高级别的顺序:

  1. 按照@madbird的建议使用Foreign Funcall接口。然而,您几乎肯定不想这样做,因为利用它的包PyCall.jl已经存在;

  2. 使用上述 PyCall.jl 包调用任何 python 代码和/或包装 python 库(好吧..“大多数”..“任何”是一个危险的词)。详情如下;

  3. 由于使用 PyCall 封装 Python 库非常简单,最重要的 Python 库已经封装在 Julia 中,例如 Pandas.jl 中的 Pandas、ScikitLearn.jl 中的 Scikit-learn 等。如果您需要它们,使用对应的Julia包即可。

如何使用PyCall.jl调用Python代码和库。

注意:以下摘录自我的《Julia Quick Syntax Reference》一书(Apress,2019)

朱莉娅⇄Python

在 Julia 中调用 Python 代码的“标准”方法是使用 PyCall 包。 它的一些不错的功能是:(a)它可以自动下载并安装 Julia 私有的 Python 本地副本,以避免混淆我们“主”Python 安装的版本依赖性,并在 Linux、Windows 中提供一致的环境和 MacOS; (b) 它提供 Julia 和 Python 类型之间的自动转换; (c) 使用起来非常简单。

关于第一点,

PyCall
在Windows和MacOS中默认安装“私有”Python环境,而在Linux中它将使用系统默认的Python环境。 + 我们可以使用(在 Julia 提示符下)
ENV["PYTHON"]="blank or /path/to/python"; using Pkg; Pkg.build("PyCall");
覆盖此类行为,其中,如果环境变量为空,
PyCall
将安装“私有”版本的 Python。

考虑到大量的 Python 库,难怪

PyCall
是最常见的 Julia 包之一。

在 Julia 程序中嵌入 Python 代码

在 Julia 程序中嵌入 Python 代码与我们在 C++ 中看到的类似,只是我们(大多数情况下)不需要考虑转换数据。我们都使用

py"..."
定义和调用 Python 函数,并且在函数调用中我们可以直接使用我们的 Julia 数据:

using PyCall
py"""
def sumMyArgs (i, j):
  return i+j
def getNElement (n):
  a = [0,1,2,3,4,5,6,7,8,9]
  return a[n]
"""
a = py"sumMyArgs"(3,4)          # 7
b = py"sumMyArgs"([3,4],[5,6])  # [8,10]
typeof(b)                       # Array{Int64,1}
c = py"sumMyArgs"([3,4],5)      # [8,9]
d = py"getNElement"(1)          # 1

请注意,即使是像数组这样的复杂数据,我们也不需要进行转换,结果会转换回 Julia 类型。 对于数字、布尔值、字符串、IO 流、日期/周期和函数类型以及这些类型的元组、数组/列表和字典,类型转换是自动的。其他类型会转换为通用

PyObject
类型。

注意上一个示例的最后一行,

PyCall
不会尝试索引转换(Python 数组是从 0 开始的,而 Julia 数组是从 1 开始的):使用“1”作为参数调用 python
getNElement()
函数将检索 在 Python 中 是数组的元素“1”。

使用Python库

使用 Python 库也很简单,如下面的示例所示,使用 ezodf 模块创建 OpenDocument 电子表格(ODS 文档的

ezodf
包装器 - 内部使用 PyCall - 已经存在,OdsIO ).

在尝试复制以下代码之前,请确保

ezodf
模块可用于您在 Julia 中使用的 Python 环境。如果这是一个独立的环境,只需按照Python的方式安装包(例如使用
pip
)。如果您使用“私有”Conda 环境,则可以使用 Conda.jl 包并输入
using Conda; Conda.add_channel("conda-forge"); Conda.add("ezodf")

const ez = pyimport("ezodf")  # Equiv. of Python `import ezodf as ez`
destDoc = ez.newdoc(doctype="ods", filename="anOdsSheet.ods")
sheet = ez.Sheet("Sheet1", size=(10, 10))
destDoc.sheets.append(sheet)
dcell1 = get(sheet,(2,3)) # Equiv. of Python `dcell1 = sheet[(2,3)]`. This is cell "D3" !
dcell1.set_value("Hello")
get(sheet,"A9").set_value(10.5) # Equiv. of Python `sheet['A9'].set_value(10.5)`
destDoc.backup = false
destDoc.save()

该模块在 Julia 中的使用遵循 Python API,几乎没有语法差异。 该模块已导入并分配给更短的别名

ez
。 然后我们可以使用常用的 Python 语法直接调用它的函数
module.function()
doc
返回的
newdoc
对象是通用
PyObject
类型。然后我们可以分别使用
myPyObject.attribute
myPyObject.method()
访问其属性和方法。 在我们无法直接访问某些指示值的情况下,例如
sheet[(2,3)]
(其中索引是一个元组),我们可以调用
get(object,key)
函数。 + 最后,再次注意,索引转换不是自动实现:当请求
get(sheet,(2,3))
时,这些被解释为基于Python的索引,并且返回电子表格的单元格
D3
,而不是
B2


1
投票

我想Foreign Funcall Interface 就是您正在寻找的。这是 Julia 的示例。更多信息请参见 PyCall.jl 存储库。

© www.soinside.com 2019 - 2024. All rights reserved.