我使用 numpy、pandas、scikit-learn 在 Python 中编写了一些代码。是否可以从 Julia 程序调用此 Python 代码?
Ant*_*llo 12
我认为你可以考虑三种不同的方式从 Julia 调用 Python 代码,按照从最低级别到最高级别的顺序排列:
\n按照 @madbird 的建议使用外国 Funcall 接口。然而,您几乎肯定不想这样做,因为利用它的包PyCall.jl已经存在;
\n使用上述 PyCall.jl 包调用任何 python 代码和/或包装 python 库(好吧..“大多数”..“任何”是一个危险的词)。详情如下;
\n由于使用 PyCall 封装 Python 库非常简单,最重要的 Python 库已经封装在 Julia 中,例如Pandas.jl中的 Pandas 、ScikitLearn.jl中的 Scikit-learn等。如果您需要它们,只需使用相应的 Julia包裹。
\n注:以下内容摘自我的《Julia Quick Syntax Reference》一书(Apress,2019)
\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。
PyCall
鉴于 Python 库数量巨大,它成为最常见的 Julia 包之一也就不足为奇了。
在 Julia 程序中嵌入 Python 代码与我们在 C++ 中看到的类似,只是我们(大多数情况下)不需要考虑转换数据。我们都使用 定义和调用 Python 函数py"..."
,并且在函数调用中我们可以直接使用我们的 Julia 数据:
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
类型。
请注意,上一个示例的最后一行PyCall
不会尝试索引转换(Python 数组是从 0 开始的,而 Julia 数组是从 1 开始的):使用getNElement()
“1”作为参数调用 python 函数将检索Python 中的值数组的元素“1”。
使用 Python 库也很简单,如下面的示例所示,使用ezodf模块创建 OpenDocument 电子表格(ezodf
ODS 文档的包装器 - 内部使用 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`\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
.