将Python与Elixir混合

将Python与Elixir混合

使用Elixir应用程序中的Python模块生成和解码QRCode

运行Elixir的Erlang VM对于特定领域的应用程序非常有效,但在其他操作(如数据处理和计算量大的东西)上却不足。 另一方面,Python具有丰富的软件包,用于处理数据处理和科学计算。

幸运的是,Erlang VM允许使用Erlang端口协议与其他语言进行互操作。

ErlPort是Elixir的库,它使使用Erlang端口协议将Erlang连接到许多其他编程语言变得更加容易。 目前,Erlport支持PythonRuby

在这篇文章中,我们将看到如何直接从Elixir应用程序调用Python模块来生成QRCode。

Erlport Python入门
要使用Erlport,只需添加您的依赖项

#mix.exs
{:erlport, "~> 0.9"}

将Erlport添加到您的项目后,您可以在Elixir代码中访问: python模块。 这个Erlport python模块允许您启动Elixir进程来执行python代码。

#creates and Elixir process for calling python functions
{:ok, pid} = :python.start()
#get the current python version
:python.call(pid, :sys, :'version.__str__', [])

更好的是,Erlport允许您配置python路径,以便您可以
从特定目录加载自定义python模块!

#Automatically load all modules in directory with path /custom/modules/directory
{:ok, pid} = :python.start([{:python_path, '/custom/modules/directory'}])

使用从调用start/1返回的过程,您可以使用熟悉的MFA 模块函数参数格式在python模块中调用函数

{:ok, pid} = :python.start([{:python_path, 'custom_modules_directory'}])
module = :test #python module to call
function = :hello # function in module
arguments = ["World"] # list of arguments pass to function the function
result = :python.call(p, module, function, arguments)

如果python函数返回数据,它将绑定到上面代码中的result变量。 否则,对于不返回任何数据的python函数, :python.call/4返回:undefined

让我们创建Elixir项目
在这个项目中,我们将创建一个简单的应用程序,将字符串编码为QRCode图像。 然后解码QRCode图像文件以返回字符串。 而不是使用本机的Elixir / Erlang库,我们将从应用程序中调用Python模块( qrtools )进行编码和解码。 检查此处设置qrtools。

1. 创建Elixir OTP应用

$ mix new elixir_python_qrcode 

2. 添加依赖

erlport添加到依赖项mix.exs

defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
{:erlport, "~> 0.9"} ,
]
end

然后安装项目依赖项。

$ mix deps.get

3. 让我们为Erlport添加包装Elixir模块

创建lib/helper.ex ,并添加名为ElixirPythonQrcode.Helper Elixir模块,并添加这些帮助器函数。

defmodule ElixirPythonQrcode.Helper do
@doc """
## Parameters
- path: directory to include in python path (charlist)
"""
def python_instance(path) when is_list(path) do
{:ok, pid} = :python.start([{:python_path, to_charlist(path)}])
pid
end

def python_instance(_) do
{:ok, pid} = :python.start()
pid
end

@doc """
Call python function using MFA format
"""
def call_python(pid, module, function, arguments \\ []) do
pid
|>:python.call(module, function, arguments)

end
end

4. 添加主模块代码。

我们将有两个函数encode/2 —包含一些字符串和文件路径。 它对数据进行编码,然后将QRCode图像写入给定的文件路径,然后decode/1 —将QRCode图像的文件路径输入并解码以获取原始数据。

让我们编辑lib/elixir_python_qrcode.ex

lib/elixir_python_qrcode.ex
defmodule ElixirPythonQrcode do
@moduledoc """
Documentation for ElixirPythonQrcode.
"""
alias ElixirPythonQrcode.Helper

def encode(data, file_path) do
call_python(:qrcode, :encode, [data, file_path])
end

def decode(file_path) do
call_python(:qrcode, :decode, [file_path])
end
  defp default_instance() do
#Load all modules in our priv/python directory
path = [:code.priv_dir(:elixir_python_qrcode), "python"]
|> Path.join()
Helper.python_instance(to_charlist(path))
end

# wrapper function to call python functions using
# default python instance
defp call_python(module, function, args \\ []) do
default_instance()
|> Helper.call_python(module, function, args)
end
end

5. 现在让我们创建我们的python模块

创建priv/python/qrcode.py模块,其中将包含我们的python函数。 这些函数处理实际的QRCode生成和解码。

priv/python/qrcode.py
def decode(file_path):
import qrtools
qr = qrtools.QR()
qr.decode(file_path)
return qr.data

def encode(data, file_path):
import qrtools
qr = qrtools.QR(data.encode("utf-8"))
return qr.encode(filename=file_path)

6.让我们测试一下我们的代码。

$ iex -S mix
iex(1)> ElixirPythonQrcode.encode("Some test to encode", "qrcode.png")
0
iex(2)> ElixirPythonQrcode.decode("qrcode.png")
'Some test to encode'
iex(3)> ElixirPythonQrcode.decode("qrcode.png") |> to_string()
"Some test to encode"

而已。 查看github仓库

编码愉快!

查阅第二部分,了解Elixir和Python之间的异步通信

From: https://hackernoon.com/mixing-python-with-elixir-7a2b7ac6696