概述

使用rust-cpython将rust程序做为python模块调用;

通常为了提高python的性能;

参考

https://github.com/dgrunwald/rust-cpython

创建rust lib库

cargo new rust2py --lib

或者使用IDE创建一个rust lib库项目

Cargo.toml

[package]
name = "rust2py"
version = "0.1.0"
edition = "2018" [lib]
name = "rust2py"
crate-type = ["cdylib"] [dependencies.cpython]
version = "0.3"
features = ["extension-module"]

lib.rs

#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
} #[macro_use]
extern crate cpython; use cpython::{PyResult, Python, py_module_initializer, py_fn}; pub fn print_str(a: String) -> String {
print!("{:#?}",a);
a
} pub fn print_str_py(_: Python, a: String) -> PyResult<String>{
let mm = print_str(a);
Ok(mm)
} // logic implemented as a normal rust function
fn sum_as_str(a:i64, b:i64) -> String {
format!("{}", a + b).to_string()
} // rust-cpython aware function. All of our python interface could be
// declared in a separate module.
// Note that the py_fn!() macro automatically converts the arguments from
// Python objects to Rust values; and the Rust return value back into a Python object.
fn sum_as_str_py(_: Python, a:i64, b:i64) -> PyResult<String> {
let out = sum_as_str(a, b);
Ok(out)
} py_module_initializer!(rust2py, init_rust2py, PyInit_rust2py, |py, m| {
m.add(py, "__doc__", "This module is implemented in Rust.")?;
m.add(py, "print_str", py_fn!(py, print_str_py(a: String)))?;
m.add(py, "sum_as_str", py_fn!(py, sum_as_str_py(a: i64, b:i64)))?;
Ok(())
});

注意:py_module_initializer方法的参数的中rust2py一定要与模块的名称一致,这个不是随便写的字符串名称,比如PyInit_rust2py就表示将来在python中调用的模块名称是rust2py

编译并复制到python的模块

cargo build
cp target/debug/librust2py.so /opt/app/anaconda3/lib/python3.8/site-packages/rust2py.so

注意:复制到python模块的so没有lib前缀

可以换一个正规的python模块名称, 效果是一样的, 但这样的名字看起来更"专业"一点 ^_^

ai@aisty:/opt/app/anaconda3/envs/py37/lib/python3.7/site-packages$ mv rust2py.so rust2py.cpython-37m-x86_64-linux-gnu.so
ai@aisty:/opt/app/anaconda3/envs/py37/lib/python3.7/site-packages$ ll rust2py.cpython-37m-x86_64-linux-gnu.so
-rwxrwxr-x 1 ai ai 5101552 12月 2 10:52 rust2py.cpython-37m-x86_64-linux-gnu.so*

封装一个自动安装的脚本install.sh

#!/bin/bash

cd /opt/wks/rust/rfil/rust2py/
/home/ai/.cargo/bin/cargo build
cp target/debug/librust2py.so /opt/app/anaconda3/envs/py37/lib/python3.7/site-packages/rust2py.cpython-37m-x86_64-linux-gnu.so

每次修改,执行一下脚本就会覆盖上一次的结果

(py37) ai@aisty:/opt/wks/rust/rfil/rust2py$ chmod +x install.sh
(py37) ai@aisty:/opt/wks/rust/rfil/rust2py$ ./install.sh

其他安装参考

https://github.com/PyO3/setuptools-rust

python调用模块

ai@aisty:/opt/app/anaconda3/lib/python3.8/site-packages$ python3.8
Python 3.8.5 (default, Sep 4 2020, 07:30:14)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import rust2py
>>> rust2py.sum_as_str(2,5)
'7'
>>> rust2py.print_str("from rust")
'from rust'
>>>

接下来添加一个稍微复杂的方法:统计列表中元素的个数,输入Python列表,返回Python字典

fn elem_count(py: Python, pl: PyList) -> PyResult<PyDict> {
let dt = PyDict::new(py);
for e in pl.iter(py) {
let el = &e;
let ct = dt.contains(py,el).unwrap(); if ct {
let a = dt.get_item(py,el).unwrap().extract::<i32>(py).unwrap() + 1 ;
dt.set_item(py,el,a)?;
}else {
dt.set_item(py,el,1)?;
} }
Ok(dt)
} // https://dgrunwald.github.io/rust-cpython/doc/src/cpython/objects/dict.rs.html#129-143 py_module_initializer!(rust2py, init_rust2py, PyInit_rust2py, |py, m| {
m.add(py, "__doc__", "This module is implemented in Rust.")?;
m.add(py, "print_str", py_fn!(py, print_str_py(a: String)))?;
m.add(py, "sum_as_str", py_fn!(py, sum_as_str_py(a: i64, b:i64)))?;
m.add(py, "hello", py_fn!(py, hello_py()))?;
m.add(py, "elem_count", py_fn!(py, elem_count(pl: PyList)))?;
Ok(())
});

rust中的python方法通常返回一个PyResult,这是一个Python对象或Python异常的枚举,使用.unwrap()将之解析为一个Python对象,然后就可以调用Python对象的方法了,这些方法可以从后面介绍的文档上查看

>>> import rust2py
>>> rust2py.elem_count([1,2,3])
{1: 1, 2: 1, 3: 1}
>>> rust2py.elem_count([1,2,3,3])
{1: 1, 2: 1, 3: 2}

更多数据类型方法请参考

http://dgrunwald.github.io/rust-cpython/doc/cpython/

如果想知道更多的关于如何使用一个Py对象的细节,请看上面文件源码

每个py对象,后面都有一个[src]的标记,这是个超链接,点开之后会转向源码,比如PyDict,源码中有测试代码,对用法学习很有帮助

https://dgrunwald.github.io/rust-cpython/doc/src/cpython/objects/dict.rs.html#129-143

    #[test]
fn test_items_list() {
let gil = Python::acquire_gil();
let py = gil.python();
let mut v = HashMap::new();
v.insert(7, 32);
v.insert(8, 42);
v.insert(9, 123);
let dict = v.to_py_object(py);
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
let mut value_sum = 0;
for el in dict.items_list(py).iter(py) {
let tuple = el.cast_into::<PyTuple>(py).unwrap();
key_sum += tuple.get_item(py, 0).extract::<i32>(py).unwrap();
value_sum += tuple.get_item(py, 1).extract::<i32>(py).unwrap();
}
assert_eq!(7 + 8 + 9, key_sum);
assert_eq!(32 + 42 + 123, value_sum);
}

看源码,是最直接,直达本质的快捷学习通道!

全代码

#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
} #[macro_use]
extern crate cpython; use cpython::{PyResult, Python, PyDict, py_module_initializer, py_fn, PyList}; pub fn print_str(a: String) -> String {
print!("{:#?}",a);
a
} pub fn print_str_py(_: Python, a: String) -> PyResult<String>{
let mm = print_str(a);
Ok(mm)
} // logic implemented as a normal rust function
fn sum_as_str(a:i64, b:i64) -> String {
format!("{}", a + b).to_string()
} // rust-cpython aware function. All of our python interface could be
// declared in a separate module.
// Note that the py_fn!() macro automatically converts the arguments from
// Python objects to Rust values; and the Rust return value back into a Python object.
fn sum_as_str_py(_: Python, a:i64, b:i64) -> PyResult<String> {
let out = sum_as_str(a, b);
Ok(out)
} fn hello_py(py: Python) -> PyResult<String> {
let sys = py.import("sys")?;
let version: String = sys.get(py, "version")?.extract(py)?; let locals = PyDict::new(py);
locals.set_item(py, "os", py.import("os")?)?;
let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract(py)?; let res = format!("Hello {}, I'm Python {}", user, version).to_string();
let res = res.replace("\n","");
Ok(res)
} fn elem_count(py: Python, pl: PyList) -> PyResult<PyDict> {
let dt = PyDict::new(py);
for e in pl.iter(py) {
let el = &e;
let ct = dt.contains(py,el).unwrap();
// let ct2 = match ct {
// Ok(b) => b,
// Err(e) => return Err(e),
// }; if ct {
let a = dt.get_item(py,el).unwrap().extract::<i32>(py).unwrap() + 1 ;
dt.set_item(py,el,a)?;
}else {
dt.set_item(py,el,1)?;
} }
Ok(dt)
} // https://dgrunwald.github.io/rust-cpython/doc/src/cpython/objects/dict.rs.html#129-143 py_module_initializer!(rust2py, init_rust2py, PyInit_rust2py, |py, m| {
m.add(py, "__doc__", "This module is implemented in Rust.")?;
m.add(py, "print_str", py_fn!(py, print_str_py(a: String)))?;
m.add(py, "sum_as_str", py_fn!(py, sum_as_str_py(a: i64, b:i64)))?;
m.add(py, "hello", py_fn!(py, hello_py()))?;
m.add(py, "elem_count", py_fn!(py, elem_count(pl: PyList)))?;
Ok(())
});

4.1 python中调用rust程序的更多相关文章

  1. Python中调用其他程序的方式

    前言 在Python中,可以方便地使用os模块来运行其他脚本或者程序,这样就可以在脚本中直接使用其他脚本或程序提供的功能,而不必再次编写实现该功能的代码.为了更好地控制运行的进程, 可以使用win32 ...

  2. Python中调用Java程序包

    <原创不易,转载请标明出处:https://www.cnblogs.com/bandaobudaoweng/p/10785766.html> 开发Python程序,需求中需要用到Java代 ...

  3. 使用ctypes在Python中调用C++动态库

    使用ctypes在Python中调用C++动态库 入门操作 使用ctypes库可以直接调用C语言编写的动态库,而如果是调用C++编写的动态库,需要使用extern关键字对动态库的函数进行声明: #in ...

  4. PySpark 的背后原理--在Driver端,通过Py4j实现在Python中调用Java的方法.pyspark.executor 端一个Executor上同时运行多少个Task,就会有多少个对应的pyspark.worker进程。

    PySpark 的背后原理 Spark主要是由Scala语言开发,为了方便和其他系统集成而不引入scala相关依赖,部分实现使用Java语言开发,例如External Shuffle Service等 ...

  5. Python脚本传參和Python中调用mysqldump

    Python脚本传參和Python中调用mysqldump<pre name="code" class="python">#coding=utf-8 ...

  6. SQL点滴15—在SQL Server 2008中调用C#程序

    原文:SQL点滴15-在SQL Server 2008中调用C#程序 T-SQL的在执行普通的查询的时候是很高效的,但是在执行循环,判断这样的语句的时候效率就不那么的高了.这时可以借助CLR了,我们可 ...

  7. Django之在Python中调用Django环境

    Django之在Python中调用Django环境 新建一个py文件,在其中写下如下代码: import os if __name__ == '__main__': os.environ.setdef ...

  8. (转)python中调用R语言通过rpy2 进行交互安装配置详解

    python中调用R语言通过rpy2 进行交互安装配置详解(R_USER.R_HOME配置) 2018年11月08日 10:00:11 luqin_ 阅读数:753   python中调用R语言通过r ...

  9. Python中调用自然语言处理工具HanLP手记

    手记实用系列文章: 1 结巴分词和自然语言处理HanLP处理手记 2 Python中文语料批量预处理手记 3 自然语言处理手记 4 Python中调用自然语言处理工具HanLP手记 5 Python中 ...

随机推荐

  1. uni-app(Vue)中(picker)用联动(关联)选择以至于完成某些功能

    如下图所示,在项目中需求是通过首先选择学生的专业,选好之后在每个专业下面选择对应的学期,每个学期有对应的学费,因此就需要联动选择来实现这一功能. 以下仅展示此功能主要代码: <div class ...

  2. Can't open PID file /run/zabbix/zabbix_agentd.pid

    神奇的事情,重启主机(reboot)后查看状态是正常的没有报错,重启zabbix-agent后,报无法打开zabbix_agentd.pid,zabbix-web正常监控 1.首先,/etc/zabb ...

  3. idea使用git更新代码 : update project(git merge、git rebase)

    idea使用git更新代码 : 选中想要更新的项目,右键点击 git => repository => pull 这样使用一次后idea会自动建立选中分支的远程跟踪分支,以后可直接点击下图 ...

  4. PTA 6-1 求采用邻接矩阵作为存储结构的无向图各顶点的度 (6分)

    PTA 6-1 求采用邻接矩阵作为存储结构的无向图各顶点的度 (6分) 函数接口定义: 函数接口为: void dgree(MGraph G); G为采用邻接矩阵作为存储结构的有向图 裁判测试程序样例 ...

  5. EDG夺冠!用Python分析22.3万条数据:粉丝都疯了!

    一.EDG夺冠信息 11月6日,在英雄联盟总决赛中,EDG战队以3:2战胜韩国队,获得2021年英雄联盟全球总决赛冠军,这个比赛在全网各大平台也是备受瞩目: 1.微博热搜第一名,截止2021-11-1 ...

  6. 2021 数字四川创新大赛WriteUp

    数字四川初赛+复赛wp Web easyphp http://111.9.220.114:50006/.index.php.swp 备份文件泄漏 <?php #error_reporting(0 ...

  7. (一)初识MySQL

    JavaEE:企业级Java开发  Web 前端(页面:展示,数据) 后台(连接点,连接数据库JDBC,链接前端(控制,控制视图跳转和给前端传递数据)) 数据库(存数据,Txt,Excel,word) ...

  8. dart系列之:dart类中的泛型

    目录 简介 为什么要用泛型 怎么使用泛型 类型擦除 泛型的继承 泛型方法 总结 简介 熟悉JAVA的朋友可能知道,JAVA在8中引入了泛型的概念.什么是泛型呢?泛型就是一种通用的类型格式,一般用在集合 ...

  9. 浏览器 Proxy SwitchyOmega 插件设置代理访问内网服务器

    使用Proxy SwitchyOmega 插件通过代理 直接访问到内网网站 一.使用场景 如下图所示,如果在电脑的网络设置中开启代理,每次更换代理就需要进入这里设置改变代理.且我们可能回需求到两个网页 ...

  10. [spojQTREE6]Query on a tree VI

    考虑如下构造: 新建一条边$(0,1)$,并将原树以0为根建树,记$fa_{x}$为$x$的父亲(其中$1\le x\le n$) 维护两棵森林,分别记作$T_{0/1}$,每一条边恰属于一棵,其中$ ...