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

在Rust的PyO3中如何让自定义Python类结构体正确检查实例类型?

问题描述

我正在为一个重度依赖MessagePack的老旧Python项目开发自定义MessagePack序列化器。受GIL限制,计划用Rust实现批量序列化以提升性能,目前已支持基础Python类型,但不想移植项目中的自定义Python类到Rust,打算保留标准Python MessagePack库作为降级方案。

我编写了代表单例类FinalRule的结构体PyFinalRule,期望通过PyFinalRule::is_type_of检查PyAny对象是否为FinalRule实例,但该方法对FinalRule实例始终返回false,仅在传入其类型对象时返回true,需要解决实例类型的正确检查问题。

代码示例
struct PyFinalRule(PyAny);
unsafe impl PyTypeInfo for PyFinalRule {
    const NAME: &'static str = "FinalRule";
    const MODULE: Option<&'static str> = Option::Some("LiSE.util");
    type AsRefTarget = PyAny;

    fn type_object_raw(py: Python<'_>) -> *mut PyTypeObject {
        let modu = py.import("LiSE.util").unwrap();
        let final_rule = modu.getattr("FinalRule").unwrap();
        final_rule.get_type_ptr()
    }
}
unsafe impl PyNativeType for PyFinalRule {}
解决方案

问题根源在于默认的is_type_of实现会直接对比对象的类型指针与type_object_raw返回的指针,而FinalRule实例的类型指针指向的是FinalRule类本身,只有当传入对象是类本身时才会匹配,实例自然返回false。

需要手动实现PyTypeCheck trait,重写is_type_of方法,调用Python原生的实例检查逻辑来判断对象是否为FinalRule实例:

修改后的完整代码

use pyo3::prelude::*;
use pyo3::class::PyTypeCheck;

struct PyFinalRule(PyAny);

unsafe impl PyTypeInfo for PyFinalRule {
    const NAME: &'static str = "FinalRule";
    const MODULE: Option<&'static str> = Some("LiSE.util");
    type AsRefTarget = PyAny;

    fn type_object_raw(py: Python<'_>) -> *mut pyo3::ffi::PyTypeObject {
        let modu = py.import("LiSE.util").unwrap();
        let final_rule = modu.getattr("FinalRule").unwrap();
        final_rule.get_type_ptr()
    }
}

impl PyTypeCheck for PyFinalRule {
    fn is_type_of(object: &PyAny) -> bool {
        let py = object.py();
        // 优雅处理导入和属性获取的错误,避免unwrap panic
        match py.import("LiSE.util") {
            Ok(modu) => match modu.getattr("FinalRule") {
                Ok(fr_type) => object.is_instance(fr_type).unwrap_or(false),
                Err(_) => false,
            },
            Err(_) => false,
        }
    }
}

关键说明

  1. 移除PyNativeType实现:该trait是为Rust实现的Python原生类型设计的,对于包装Python侧类的场景不需要,会干扰默认类型检查逻辑。
  2. 重写is_type_of:通过object.is_instance(fr_type)调用Python原生的isinstance逻辑,这是检查Python对象是否属于某个类实例的标准方式,能正确识别FinalRule的实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:29:55