前言:
目前朋友们对“python多个项目如何共用代码”大致比较珍视,朋友们都想要了解一些“python多个项目如何共用代码”的相关资讯。那么小编在网上网罗了一些关于“python多个项目如何共用代码””的相关内容,希望兄弟们能喜欢,咱们一起来了解一下吧!在在 2021 年Stack Overflow 年度开发者调查[1] 中,Rust 被评为“最受欢迎的语言”(连续第六年!),Python 被评为“最受欢迎”的语言。那么为什么不混合两种语言呢!本次介绍将建立一个结合 Python 和 Rust 代码的混合项目。
为什么?Python 解释方法和动态类型加速了我们的开发工作流程。但是对于更复杂的工作,我们经常会遇到性能问题。
Rust 是实现 Python 项目本机性能升级的理想选择。本机优化使用低级语言和编译器绕过 Python 解释器。
通过结合 Rust 和 Python,您可以获得两全其美:使用 Python 的快速交互式开发环境和使用 Rust 的本机性能。
Python + Rust 项目 — 作者的图片
为什么在同一个项目中使用两种语言?
在以下部分中,我将设置一个混合 Python/Rust 项目的示例。我们的项目将在同一个项目和工件中结合 Python 代码和 Rust。
混合项目的好处是显而易见的:您在同一个存储库中共享您的 Rust 和 Python 代码并创建一个工件。结果,您将两种语言结合在同一个项目中;使用原生 Rust 组件迭代和扩展 Python 代码变得更加容易。此外,只需部署一个工件,就可以更轻松地维护和共享您的项目。
缺点很明显:两种语言在同一个目录下,如何构建、测试和部署这样的项目?
如何?PyO3 + 成熟素
集成 Rust 和 Python 的主要方式是PyO3 框架。使用 PyO3,我们可以用 Rust 编写原生 Python 模块。当然,该框架也支持从 Rust 调用 Python,但我将只关注使用原生 Rust 模块扩展 Python。
PyO3 将您的 Rust 代码包装到本机 python 模块中。因此,绑定生成很容易且完全透明。
棘手的部分是构建混合 Python 和本机代码项目(Python + [Rust、C 或 C++])时代码的打包。那么如何制作集成 Python 和原生代码的轮子呢?
Python代码无需编译即可分发,与平台无关;安装轮子会.pyc即时创建文件(Python 字节码)。但是我们的 Rust 代码需要编译和分发为共享库(二进制代码)。
打包是这个项目的难点:创建一种通用的、多平台的方式来生成混合 Python-Rust 包。
可以帮助您实现此目的的工具是Maturin。Maturin 管理创建、构建、打包和分发混合 Python/Rust 项目。
PyO3 + Maturin — 图片作者
使用 Maturin 初始化一个混合项目
首先,使用pip.
$ pip 安装成熟
它包括maturin二进制文件,一个命令行界面。
$ maturin --help maturin 0.12.9使用 pyo3、rust-cpython 和 cffi 绑定以及 rust 二进制文件作为python 包构建和发布 crates用法: maturin <SUBCOMMAND>选项: -h,--help 打印帮助信息 -V, --version 打印版本信息SUBCOMMANDS: build 将 crate 构建到 python 包 中 develop 将 crate 作为模块安装在当前 virtualenv help 打印此消息或给定子命令的帮助 init 在现有目录 列表中创建一个新的货物项目-python 搜索并列出可用的 python 安装 new 创建一个新的 cargo 项目 publish 构建并将 crate 作为 python 包发布到 pypi sdist 只构建一个源分发(sdist)而不编译 上传 将 python 包上传到 pypi
可执行文件提出了maturin几个选项。让我们放大构建和开发。
build:编译 Rust 并将其与 Python 包集成。它生成一个 Wheel 包,将 Rust 生成的二进制工件与最终的 Python 代码混合在一起。develop:在开发和调试项目时很有用。此命令直接在 Python 模块中构建和安装新创建的共享库。
为了测试一个混合的 Rust-Python 项目,我们现在可以使用maturin new命令初始化我们的库。
$ maturin new --help maturin-new创建一个新的货物项目用法: maturin new [OPTIONS] <PATH> ARGS: <PATH> 项目路径OPTIONS: -b, --bindings <BINDINGS> 使用哪种绑定 [可能values: pyo3, rust-cpython, cffi, bin] -h, --help 打印帮助信息 --mixed 使用混合Rust/Python项目布局 --name <NAME> 设置生成的包名,默认为目录名
对于我们的项目,我们使用选项--bindings pyo3和--mixed my_project. 该my_project参数与此示例的目标项目目录匹配。
$ maturin new --bindings pyo3 --mixed my_project
生成的项目将目录中的 Python 包my_project与 Rust 项目定义Cargo.toml和基于 Rust 的src目录集成在一起。
$ tree my_project my_project ├── Cargo.toml ├── my_project │ └── __init__.py ├── pyproject.toml ├── src │ └── lib.rs └── test └── test.py 3个目录, 5 个文件
好的,我们有了基本的项目骨架。我们现在可以添加一个简单的 Rust 函数来公开。
项目结构 — 作者图片
用 PyO3 包装 Python 代码
我们需要在 Python 运行时可调用的 Python 模块中声明和导出 Rust 函数。我们首先使用#[pymodule]Rust 宏创建一个模块。在我们的函数中,my_project我们将声明 Rust 和 Python 之间的绑定。
→ 锈«my_project/src/lib.rs» =使用pyo3::prelude::*; (1) (2) <<functions>>#[pymodule] fn my_project(_py: Python , m: & PyModule ) -> PyResult <()> { (3) <<function_declarations>> Ok(())} ( 4) <<测试>>(1)我们包括Py03定义和宏。(2)在<<functions>>块中,我们声明了我们的 Rust 函数。(3)在<<function_declarations>>块中,我们在最终的 Python 模块中公开我们的 Rust 函数。(4)在<<tests>>块中,我们添加了 Rust 单元测试函数。一个简单的函数
让我们从<<functions>>块的简单函数开始。我们的导出函数is_prime通过将其除以前面的数字来检查其输入的素数。对于数字num,我们检查 2 和 之间数字的除法余数√num。
→ rust «functions» = #[pyfunction] (1) fn is_prime(num: u32) -> bool { match num { 0 | 1 => false , _ => { let limit = (num as f32).sqrt() as u32 ; (2) (2..=limit).any(|i| num % i == 0) == false (3) } }}(1) Rust 宏#[pyfunction]为 Python 绑定生成代码。(2)计算我们的试除数系列的上限。(3)生成试验并测试除法的其余部分。2..=limit生成介于2和limit(包括)之间的范围。any检查生成的元素之一是否满足谓词。
在<<function_declarations>>块中,我们将函数添加到导出的模块中。
→ 锈«function_declarations» = m.add_function(wrap_pyfunction!(is_prime, m)?)?;
在该<<tests>>块中,我们添加了一些简单的单元测试。
→ rust «tests» = #[cfg(test)] mod 测试{ 使用 super ::*; #[测试] fn simple_test_false() { assert_eq!(is_prime(0), false ); assert_eq!(is_prime(1), false ); assert_eq!(is_prime(12), false ) } #[test] fn simple_test_true() { assert_eq!(is_prime(2), true ); assert_eq!(is_prime(3), true ); assert_eq!(is_prime(41), true ) }}构建并运行您的 Python 模块
使用 Maturin,构建一个原生 Rust 模块并将其导出到 Python 解释器中只需一行代码。
$ cd my_project $ maturin 开发
该命令构建 Rust 原生模块并将其部署在当前的 virtualenv 中。
导入 我的项目打印(我的项目.is_prime (12))打印(我的项目.is_prime (11))>假>真
在引擎盖后面,命令maturin develop:
使用 Cargo 编译原生 Rust 模块:在本地 python 模块中编译和复制共享库。安装 Python 模块:该模块安装在您的 virtualenv 中。对于无需在每次 Python 代码更改时重新构建项目的即时测试,您可以通过在( Maturin Editable Installs )中添加以下行来使用可编辑安装(ie )。pip install -epyproject.yml
[构建系统]需要 = [ "maturin>=0.12" ]构建后端 = "maturin"测试你的模块
我们可以在 Python 中添加一个简单的基于属性的测试来检查is_primeRust 函数的行为。
我们首先为Hypothesis Python 包添加一个依赖项。要将依赖项添加到我们的项目中,我们可以编辑该pyproject.toml文件。Maturin 支持PEP 621,启用 Python 元数据规范。
→ toml «my_project/pyproject.toml» = [build-system] requires = [ "maturin>=0.12" ]build-backend = "maturin" [project.optional-dependencies] test = [ "hypothesis" , "sympy" ] [project] name = " my_project " requires-python = ">=3.6"分类器 = [ "Programming Language :: Rust" , "Programming Language :: Python :: Implementation :: CPython" ,]
我们现在可以运行maturin develop命令了。
$ cd my_project $ maturin 开发 --extras 测试(1)
(1)使用--extras testMaturin 选项安装 Python 测试依赖项。
我们添加了一个简单的基于属性的测试。
→ Python «my_project/test/test.py» =从 假设 导入设置,详细程度,从 假设 导入策略作为st from sympy.ntheory import isprime import my_project @given(s=st.integers(min_value=1, max_value=2 **10))@settings(verbosity=Verbosity.normal, max_examples=500) def test_is_prime(s): assert isprime(s) == my_project.is_prime(s) if __name__ == "__main__" : test_is_prime()
我们终于可以运行基于属性的 Python 测试了。
$ cd my_project $ python test/test.py
还有我们的 Rust 测试。
$ cd my_project $ 货物测试
标签: #python多个项目如何共用代码