社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

在 Python 里用 Rust:让 Python 再次强大!

大迁世界 • 9 月前 • 144 次点击  

我有一支技术全面、经验丰富的小型团队,专注高效交付中等规模外包项目,有需要外包项目的可以联系我

Python 与 Rust 风格截然不同,但组合起来却意外合拍。在讨论如何把二者拼在一起之前,先快速认识一下 Rust。你大概听过它的名号,但未必摸清了它的“脾气”。

什么是 Rust?

Rust 属于低层语言,程序员需要更贴近机器的真实工作方式来思考。

举例:整数类型按字节位宽区分,对应 CPU 支持的类型。直觉上你或许会说:在 Rust 里  a + b 就是“一条机器指令”。但编译链太复杂,这种说法只在粗略意义上成立

Rust 的目标是零成本抽象:许多高级抽象在运行期会被编译器“抹平”,不额外付费。

例如:对象默认分配在上(除非你显式要求堆分配),因此创建原生对象没有运行期开销(尽管初始化仍然需要)。

最后,Rust 是内存安全语言。别的语言也可能提供内存安全或零成本抽象,但往往不是同一类。 内存安全并不代表“永不违规”,而是仅有两种途径会出事:

  1. 编译器报错;
  2. 你显式写了  unsafe 的代码。

标准库里确实有一些 unsafe,但远少于多数人的想象。这并不削弱前述结论:除非你(少数场景里)必须手写 unsafe大多数违规来自底层基础设施而非业务面。

为什么要用 Rust?

Rust 诞生是为同时追求效率 内存安全。在互联环境里,这个目标越来越关键。

典型场景:底层协议解析。输入常来自不可信源,既要快,又要稳。

这听起来像浏览器在做的事?没错。Rust 来自 Mozilla 基金会,最初就是为了改进 Firefox。

如今不止浏览器:常见的微服务同样要快速解析不可信数据并且保证安全。

示例:统计字符

为理解“把 Rust 包一层给 Python 用”的例子,我们先设定一个问题,满足:

  • 足够简单;
  • 能写出高性能循环;
  • 有点实际价值。

具体问题:判断 某字符在字符串里是否出现超过 X 次。这个需求用“高效正则”未必好写;即便用 Numpy 等技巧,也常需要整串扫描,而直觉算法在低层语言里会更快更易读

为了展示 Rust 的一些点,我们再加两种“重置计数”的变体:

  • 遇到换行重置(即“某行内是否超过 X 次?”)
  • 遇到空白重置(即“某个单词内是否超过 X 次?”)

枚举(enum)

Rust 的枚举很强大。这里用一个“三选一”的简单枚举,表示何时重置计数

#[derive(Copy)]
enum Reset {
    NewlinesReset,
    SpacesReset,
    NoReset,
}

结构体(struct)

结构体有点像 Python 的 dataclass,但能做的更复杂。

#[pyclass]
struct Counter {
    what: char,
    min_number: u64,
    reset: Reset, 
}

实现块(impl)

通过  impl 给结构体加方法。本例里方法再调用外部函数,方便拆分逻辑;复杂场景下编译器会内联,提升可读性同时不增加运行成本。

#[pymethods]
impl Counter {
    #[new]
    fn new(what: char, min_number: u64, reset: Reset) -> Self {
        Counter{what: what, min_number: min_number, reset: reset}
    }
    
    fn has_count(
        &self,
        data: &str,
    ) -> bool {
        has_count(self, data.chars())
    }
}

函数

Rust 变量默认不可变;计数 current_count 需要变化,所以要用  mut

fn has_count(cntr: &Counter, chars: std::str::Chars) -> bool {
    let mut current_count : u64 = 0;
    for c in chars {
        if got_count(cntr, c, &mut current_count) {
            return true;
        }
    }
    false
}

循环逐字符处理,并调用 got_count。这也演示了可变引用的传递:调用方与被调方都要显式标注可变,修改意图更清晰

计数逻辑

重置 → 自增 → 比较阈值。Rust 的语句序列以最后一个表达式的值为结果。

fn got_count(cntr: &Counter, c: char, current_count: &mut u64) -> bool {
    maybe_reset(cntr, c, current_count);
    maybe_incr(cntr, c, current_count);
    *current_count >= cntr.min_number
}

重置

这里用到了模式匹配。完整讲解可以开一门课——本例只匹配元组的若干情形:

fn maybe_reset(cntr: &Counter, c: char


    
, current_count: &mut u64) -> () {
    match (c, cntr.reset) {
        ('\n', Reset::NewlinesReset) | (' ', Reset::SpacesReset)=> {
            *current_count = 0;
        }
        _ => {}
    };
}

自增

按需比较字符并累加:

fn maybe_incr(cntr: &Counter, c: char, current_count: &mut u64) -> (){
    if c == cntr.what {
        *current_count += 1;
    };
}

注:为讲解直观,本文代码偏教学取向,并非最佳实践或完美 API 设计范式。

把 Rust 包给 Python 用

可以使用 PyO3。这个 Rust crate 通过注解把 Rust 类型/方法暴露为 Python 扩展,让两端更易同时迭代。

引用 PyO3

use pyo3::prelude::*;

包装枚举

派生 Clone/Copy 便于在 Python 侧使用与传递。

#[pyclass]
#[derive(Clone)]
#[derive(Copy)]
enum Reset {
    /* ... */
}

包装结构体

用 #[pyclass] 生成必要接口。




    
#[pyclass]
struct Counter {
    /* ... */
}

包装实现(构造器)

#[pymethods] + #[new] 指定 Python 侧的构造方法。

#[pymethods]
impl Counter {
    #[new]
    fn new(what: char, min_number: u64,
          reset: Reset) -> Self {
        Counter{what: what,
          min_number: min_number, reset: reset}
    }
    /* ... */
}

定义模块

用 #[pymodule] 指定初始化函数与导出内容。

#[pymodule]
fn counter(_py: Python, m: &PyModule
) -> PyResult {
    m.add_class::()?;
    m.add_class::()?;
    Ok(())
}

? 表示可能失败(如类未正确注册);PyResult 会在导入时转换成 Python 异常。


用 maturin 开发/构建

快速迭代:把编译后的扩展直接装到当前虚拟环境。

$ maturin develop

产出分发包

$ maturin build

会生成 manylinux 的 wheel(按 CPU 架构区分),可上传到 PyPI。

在 Python 里使用

这一部分最“丝滑”:用法几乎与纯 Python 库 别无二致。这也意味着:如果你在优化既有 Python 库,只要接口不变,原有单测就能直接覆盖到 Rust 实现。

导入

import counter

构造

我们暴露了构造器,因此可以直接在 Python 侧实例化(也可以设计成由其他函数返回)

cntr = counter.Counter(
    'c',
    3,
    counter.Reset.NewlinesReset,
)

调用

检验字符串里是否至少有三个 'c'

>>> cntr.has_count("hello-c-c-c-goodbye")
True

加入换行(触发重置),不再满足“三个 c 连续出现”:




    
>>> cntr.has_count("hello-c-c-\nc-goodbye")
False

Rust + Python,其实很容易

Press enter or click to view image in full size

本文的目的,是让你相信把 Rust 与 Python 结合并不难。 Rust 负责高性能与安全,但上手曲线更陡;Python 负责极快迭代,但存在性能上限

因此: 原型用 Python,瓶颈用 Rust。 有了 maturin,开发与发布都更顺畅:写 → 构建 → 享受组合拳


全栈AI·探索:涵盖动效、React Hooks、Vue 技巧、LLM 应用、Python 脚本等专栏,案例驱动实战学习,点击二维码了解更多详情。

图片
最后:

20个前端开发者必备的响应式布局

深入React:从基础到最佳实践完整攻略
python 技巧精讲
React Hook 深入浅出
CSS技巧与案例详解
vue2与vue3技巧合集

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/187248