首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PyO3 -导出Enum的FromPyObject

PyO3 -导出Enum的FromPyObject
EN

Stack Overflow用户
提问于 2021-05-06 06:20:20
回答 1查看 1K关注 0票数 2

我正在尝试使用PyO3 (版本: 0.13.2)从Rust构建一个Python包。现在,我被困在试图让转换工作的枚举。我有一个像这样的简单的枚举:

代码语言:javascript
复制
#[derive(FromPyObject)]
#[derive(Copy,Clone,PartialEq,Eq)]
enum Direction {
    Left,
    Right,
    Up,
    Down
}

但是,我按照#[derive(FromPyObject)]文献资料添加了以下错误:

错误:不能为空结构和变体派生FromPyObject -> src/main.rs:3:10 \x~#src(FromPyObject)_x ^若注:此错误起源于派生宏(在夜间生成中,使用-Z宏运行-回溯以获取更多信息)

在本例中,所有枚举值都具有与它们关联的类型。如果这是错误的来源,有什么方法可以绕过它,这样它就可以使用我拥有的枚举吗?

谢谢你的帮助。

溶液

这是我最后得到的解决方案。我对锈病还不熟悉,所以你要冒着风险去使用它。感谢这个问题的Ahmed为宏提供了基础。

您将需要以下依赖项。

代码语言:javascript
复制
[dependencies]
num-traits = "0.2"
num-derive = "0.3"

宏为枚举实现IntoPy和FromPyObject。它转换为/从一个int。此外,您现在可以迭代枚举!

代码语言:javascript
复制
use pyo3::prelude::*;

#[macro_use]
extern crate num_derive;
use num_traits::FromPrimitive;

// https://stackoverflow.com/questions/21371534/in-rust-is-there-a-way-to-iterate-through-the-values-of-an-enum
macro_rules! simple_enum {

    ($visibility:vis, $name:ident, $($member:tt),*) => {

        #[derive(Copy,Clone)]
        $visibility enum $name {$($member),*}

        impl $name {
            fn iterate() -> Vec<$name> {
                vec![$($name::$member,) *]
            }
        }

        impl IntoPy<PyObject> for $name {
            fn into_py(self, py: Python) -> PyObject {
                (self as u8).into_py(py)
            }
        }

        impl FromPyObject<'_> for $name {

            fn extract(ob: &'_ PyAny) -> PyResult<$name> {
        
                let value: u8 = ob.extract().unwrap();

                if let Some(val) = FromPrimitive::from_u8(value) {
                    for member in $name::iterate() {
                        if (member as u8) == val {
                            return Ok(member);
                        }
                    }
                }

                panic!("Invalid value ({}).", value);
            }
        }
    };

    ($name:ident, $($member:tt),*) => {
        simple_enum!(, $name, $($member),*)
    };
}

// Example
simple_enum!(pub, Direction, 
    Left, 
    Right, 
    Up, 
    Down
);

在Python中,您需要重新定义枚举,并在Rust模块中使用该值。

代码语言:javascript
复制
from enum import Enum
    
class Direction(Enum):
    Left = 1
    Right = 2
    Up = 3
    Down = 4
    
// Direction.Left.value
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-06 10:43:54

目前还没有这类枚举的派生。FromPyObject派生的目的是处理来自Python端的多态输入,而不是区分单元类型。

然而,自去年夏天以来,陈腐的公关一直在PyO3上添加通用枚举支持。如果这得到了一些进展,您可能会在将来处理Python。

在此之前,您需要手动实现FromPyObject,并决定哪些输入映射到哪个变体。

如果您想从Python中传递一个字符串,并从它获得与之匹配的String变量,您还可以让您的接口在Rust中接受一个impl TryFrom<&str> for Direction,添加一个impl TryFrom<&str> for Direction并在接口函数中尝试转换。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67412827

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档