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

Thi*_*dre 10 python julia

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

Ant*_*llo 12

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

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

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

    \n
  4. \n
  5. 由于使用 PyCall 封装 Python 库非常简单,最重要的 Python 库已经封装在 Julia 中,例如Pandas.jl中的 Pandas 、ScikitLearn.jl中的 Scikit-learn等。如果您需要它们,只需使用相应的 Julia包裹。

    \n
  6. \n
\n

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

\n

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

\n

朱莉娅 \xe2\x87\x84 Python

\n

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

\n

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

\n

PyCall鉴于 Python 库数量巨大,它成为最常见的 Julia 包之一也就不足为奇了。

\n将 Python 代码嵌入 Julia 程序\n

在 Julia 程序中嵌入 Python 代码与我们在 C++ 中看到的类似,只是我们(大多数情况下)不需要考虑转换数据。我们都使用 定义和调用 Python 函数py"...",并且在函数调用中我们可以直接使用我们的 Julia 数据:

\n
using PyCall\npy"""\ndef sumMyArgs (i, j):\n  return i+j\ndef getNElement (n):\n  a = [0,1,2,3,4,5,6,7,8,9]\n  return a[n]\n"""\na = py"sumMyArgs"(3,4)          # 7\nb = py"sumMyArgs"([3,4],[5,6])  # [8,10]\ntypeof(b)                       # Array{Int64,1}\nc = py"sumMyArgs"([3,4],5)      # [8,9]\nd = py"getNElement"(1)          # 1\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

请注意,上一个示例的最后一行PyCall不会尝试索引转换(Python 数组是从 0 开始的,而 Julia 数组是从 1 开始的):使用getNElement()“1”作为参数调用 python 函数将检索Python 中的值数组的元素“1”。

\n使用 Python 库\n

使用 Python 库也很简单,如下面的示例所示,使用ezodf模块创建 OpenDocument 电子表格(ezodfODS 文档的包装器 - 内部使用 PyCall - 已经存在,OdsIO)。

\n

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

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

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

\n