如何在Rust中使用PyO3从内部修改自定义rust对象的Python列表?

huangapple go评论102阅读模式
英文:

How to modify Python list of custom rust objects from within Rust with PyO3?

问题

抱歉,您的代码示例中包含HTML转义字符,我将为您提供未经转义的代码,以便更好地理解问题:

  1. use pyo3::prelude::*;
  2. #[pyclass]
  3. pub struct ListElement {
  4. pub value_sum: f32
  5. }
  6. #[pymethods]
  7. impl ListElement {
  8. #[new]
  9. fn new(value_sum: f32) -> Self {
  10. ListElement { value_sum }
  11. }
  12. fn add_value(&mut self, value: f32) {
  13. self.value_sum += value;
  14. }
  15. }
  16. #[pyfunction]
  17. fn modify_list_elements(list: Vec<&ListElement>, value: f32){
  18. for mut elem in list {
  19. elem.add_value(value);
  20. }
  21. }
  22. #[pymodule]
  23. fn my_rust_module(_py: Python, m: &PyModule) -> PyResult<()> {
  24. m.add_class::<ListElement>()?;
  25. m.add_function(wrap_pyfunction!(modify_list_elements, m)?)?;
  26. Ok(())
  27. }

Cargo.toml 文件也应该是未经HTML转义的。至于您遇到的错误,请确保您的 modify_list_elements 函数接受 Vec<&ListElement>,而不是 Vec<&amp;ListElement>。将代码中的 &lt;&amp; 更改为正常的 <&,并重新构建项目,应该能够解决这个问题。

希望这可以帮助您解决问题!如果您有其他问题,请随时提问。

英文:

I'm new to Rust and I have a problem. I have list in Python. It is a list of objects implemented in PyO3 Rust. I want to pass it to a function to make some changes to the elements.

This is minimal reproducible example:

  1. use pyo3::prelude::*;
  2. #[pyclass]
  3. pub struct ListElement {
  4. pub value_sum: f32
  5. }
  6. #[pymethods]
  7. impl ListElement {
  8. #[new]
  9. fn new(value_sum: f32) -&gt; Self {
  10. ListElement { value_sum }
  11. }
  12. fn add_value(&amp;mut self, value: f32) {
  13. self.value_sum += value;
  14. }
  15. }
  16. #[pyfunction]
  17. fn modify_list_elements(list: Vec&lt;&amp;ListElement&gt;, value: f32){
  18. for mut elem in list {
  19. elem.add_value(value);
  20. }
  21. }
  22. #[pymodule]
  23. fn my_rust_module(_py: Python, m: &amp;PyModule) -&gt; PyResult&lt;()&gt; {
  24. m.add_class::&lt;ListElement&gt;()?;
  25. m.add_function(wrap_pyfunction!(modify_list_elements, m)?)?;
  26. Ok(())
  27. }

this is my Cargo.toml

  1. [package]
  2. name = &quot;my_rust_module&quot;
  3. version = &quot;0.1.0&quot;
  4. edition = &quot;2018&quot;
  5. [lib]
  6. # The name of the native library. This is the name which will be used in Python to import the
  7. # library (i.e. `import string_sum`). If you change this, you must also change the name of the
  8. # `#[pymodule]` in `src/lib.rs`.
  9. name = &quot;my_rust_module&quot;
  10. # &quot;cdylib&quot; is necessary to produce a shared library for Python to import from.
  11. #
  12. # Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able
  13. # to `use string_sum;` unless the &quot;rlib&quot; or &quot;lib&quot; crate type is also included, e.g.:
  14. # crate-type = [&quot;cdylib&quot;, &quot;rlib&quot;]
  15. crate-type = [&quot;cdylib&quot;]
  16. [dependencies]
  17. pyo3 = { version = &quot;0.19.0&quot;, features = [&quot;extension-module&quot;] }

This is error that I get when I use

  1. maturin develop
  1. &#128279; Found pyo3 bindings
  2. &#128013; Found CPython 3.7 at C:\my_paths\python.exe
  3. &#128225; Using build options features from pyproject.toml
  4. Compiling my_rust_module v0.1.0 (C:\my_paths\my_rust_module)
  5. error[E0277]: the trait bound `Vec&lt;&amp;ListElement&gt;: FromPyObject&lt;&#39;_&gt;` is not satisfied
  6. --&gt; src\lib.rs:22:31
  7. |
  8. 22 | fn modify_list_elements(list: Vec&lt;&amp;ListElement&gt;, value: f32){
  9. | ^^^ the trait `FromPyObject&lt;&#39;_&gt;` is not implemented for `Vec&lt;&amp;ListElement&gt;`
  10. |
  11. = help: the trait `FromPyObject&lt;&#39;a&gt;` is implemented for `Vec&lt;T&gt;`
  12. = note: required for `Vec&lt;&amp;ListElement&gt;` to implement `PyFunctionArgument&lt;&#39;_, &#39;_&gt;`
  13. note: required by a bound in `extract_argument`
  14. --&gt; C:\my_paths\.cargo\registry\src\index.crates.io-6f17d22bba15001f\pyo3-0.19.0\src\impl_\extract_argument.rs:86:8
  15. |
  16. 86 | T: PyFunctionArgument&lt;&#39;a, &#39;py&gt;,
  17. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `extract_argument`
  18. For more information about this error, try `rustc --explain E0277`.

I tried to google it, understand output of rustc --explain E0277, but I still dont know how to do it.
Any help would be appreciated.

答案1

得分: 1

问题在于 Vec&lt;T&gt; 只有在 T 也实现了 FromPyObject 时才能实现,但 &amp;ListElement 并不实现该特性。

你可以通过以下两种方法之一来修复它:

  1. 派生它:

    1. #[pyclass]
    2. #[derive(FromPyObject)]
    3. pub struct ListElement {
    4. pub value_sum: f32
    5. }
  2. 改用 Vec&lt;PyRefMut&lt;ListElement&gt;&gt;,它会自动实现 FromPyObject 特性

    1. #[pyfunction]
    2. fn modify_list_elements(list: Vec&lt;PyRefMut&lt;ListElement&gt;&gt;, value: f32){
    3. for mut elem in list {
    4. elem.add_value(value);
    5. }
    6. }
英文:

The problem here is that Vec&lt;T&gt; only implements FromPyObject if T also does so, but &amp;ListElement doesn't implement that trait.

You can fix it in one of two ways:

  1. Derive it:
    1. #[pyclass]
    2. #[derive(FromPyObject)]
    3. pub struct ListElement {
    4. pub value_sum: f32
    5. }
  2. Take Vec&lt;PyRefMut&lt;ListElement&gt;&gt; instead for which FromPyObject is automatically implemented by the pyclass attribute:
    1. #[pyfunction]
    2. fn modify_list_elements(list: Vec&lt;PyRefMut&lt;ListElement&gt;&gt;, value: f32){
    3. for mut elem in list {
    4. elem.add_value(value);
    5. }
    6. }

huangapple
  • 本文由 发表于 2023年7月11日 06:07:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76657631.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定