You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PyO3加载numpy数组时遇临时引用值编译错误求助

解决PyO3加载numpy数组返回ArrayView的生命周期错误

错误原因分析

你遇到的cannot return value referencing temporary value错误,本质是生命周期不匹配:

  • PyArray2对象是在Python::with_gil的闭包内创建的,闭包执行完毕后,该对象会被Python的垃圾回收器回收。
  • ArrayView是对PyArray2内存的引用,返回闭包后就变成了悬空引用,Rust的借用检查器会直接阻止这种不安全的行为。

解决思路与代码示例

方案1:复制数据到Rust自有数组(推荐,简单安全)

将Python数组的数据复制到Rust的ndarray::Array中,这样数组内存由Rust管理,不需要依赖Python的GC,也不存在生命周期问题。

修改后的代码:

use ndarray::{array, Array, Ix2};
use numpy::PyArray2;
use pyo3::types::IntoPyDict;
use pyo3::{PyResult, Python};

pub fn load_2d_vec() -> Array<f32, Ix2> {
    let res: PyResult<Array<f32, Ix2>> = Python::with_gil(|py| {
        let np = py.import("numpy")?;
        let locals = [("np", np)].into_py_dict(py);

        let pyarray: &PyArray2<f32> = py
            .eval(r#"np.load("./test_file")"#, Some(locals), None)?
            .extract()?;

        // 将PyArray的数据复制到Rust Array,获取所有权
        let owned_array = pyarray.readonly().as_array().to_owned();

        Ok(owned_array)
    });

    res.unwrap()
}

fn main() {
    let a = load_2d_vec();
    assert_eq!(a, array![[1.0, 2.0], [3.0, 4.0]]);
}

方案2:保留Python数组引用(适合大数组,避免复制)

如果数组体积很大,不想复制数据,可以返回Py<PyArray2<f32>>(PyO3的智能指针,持有Python对象的引用,防止被GC回收),后续需要访问数据时,再进入GIL上下文生成ArrayView。

修改后的代码:

use ndarray::{array, ArrayView, Ix2};
use numpy::PyArray2;
use pyo3::types::IntoPyDict;
use pyo3::{Py, PyResult, Python};

pub fn load_2d_vec() -> Py<PyArray2<f32>> {
    let res: PyResult<Py<PyArray2<f32>>> = Python::with_gil(|py| {
        let np = py.import("numpy")?;
        let locals = [("np", np)].into_py_dict(py);

        let pyarray: &PyArray2<f32> = py
            .eval(r#"np.load("./test_file")"#, Some(locals), None)?
            .extract()?;

        // 转换为Py智能指针,持有GIL引用,确保对象不被回收
        Ok(pyarray.into())
    });

    res.unwrap()
}

fn main() {
    let py_array = load_2d_vec();
    // 需要访问数据时,再次进入GIL上下文
    let a = Python::with_gil(|py| {
        let array_view: ArrayView<'_, f32, Ix2> = py_array.as_ref(py).readonly().as_array();
        // 如果需要在GIL外使用,还是要复制;仅在GIL内操作可直接用view
        array_view.to_owned()
    });
    assert_eq!(a, array![[1.0, 2.0], [3.0, 4.0]]);
}

总结

  • 若数组规模小,优先选方案1,代码简洁且无需关注GIL和生命周期细节。
  • 若数组规模大,用方案2避免内存复制,但后续访问数据必须在Python::with_gil闭包内进行。

内容的提问来源于stack exchange,提问作者billy voiderer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 06:01:00