【问题标题】:PyO3 - passing class extending another class as a function argumentPyO3 - 传递类扩展另一个类作为函数参数
【发布时间】:2020-09-04 23:22:21
【问题描述】:

我有一个 Rust 库,我希望能够从 Python 中使用它。所以我可以使用 PyO3 进行绑定。

假设我在 Rust 中有以下库:

pub trait Animal {
    fn make_sound();
}

pub struct Dog {}

impl Animal for Dog {
    fn make_sound() {
       println!("whoof whoof");
    }
}

pub struct Cat {}

impl Animal for Cat {
    fn make_sound() {
       println!("miaauwwww");
    }
}

pub fn make_three_sounds(&impl Animal) {
    animal.make_sound();
    animal.make_sound();
    animal.make_sound();
}

该库的用户可以使用结构 Dog 和 Cat 以及函数 make_three_sounds。但他们也可以使用特性 Animal 来定义自己的动物,然后将其传递给函数 make_three_sounds。

现在,假设我希望在 Python 中使用这个库。所以我可以使用 PyO3 来制作 Rust -> Python 绑定。然而,问题是在 Python 中,这会以不同的方式实现。您将拥有一个可以扩展的类,而不是 trait。所以在 Python 中,这个库看起来像这样:

Class Animal:
    def make_sound():
        raise Error("Unimplemented abstract method")

class Dog(Animal):
    def make_sound():
        print("woaggh woafgg")

class Cat(Animal):
    def make_sound():
        print("miaaoww")

def make_three_sounds(a: Animal):
    a.make_sound()
    a.make_sound()
    a.make_sound()

为了制作一个Dog和Cat类,我只需要在Dog和Cat结构体上方使用“#[pyclass]”和“#[pymethods]”。问题在于创建一个可以扩展的 Animal 类,然后传递给函数 make_three_sounds。为了制作 Animal 类,我可以创建一个使用 Animal trait 的结构,然后在其上方添加“#[pyclass]”。

但问题是:当 Python 库的用户扩展该类 (Animal) 并将其传递给 make_three_sounds 时,它将无法工作,因为 make_three_sounds 必须接受一个实现 trait Animal 的结构,而该 Python 对象没有t 实现该特征(尽管它是扩展实现它的类/结构的类的对象)。我可以制作一个接受 PyAny 对象的 make_three_sounds 函数的包装器,但是我以后如何将该对象传递给实际的 make_three_sounds 函数?

【问题讨论】:

    标签: python inheritance rust traits pyo3


    【解决方案1】:

    我可以看到的一个解决方案如下。

    我创建了一个函数make_three_sounds(PyAny a),它将成为 Rust make_three_sounds(&impl Animal a) 函数的包装器。该包装器将接受 PyAny 类型的对象。稍后我将执行以下操作。我将有一个特殊的结构 PyAnimal 实现特征 Animal。该特征将有一个名为python_object 的属性。 Python 中的 PyAny 对象(表示扩展 Animal 的类的对象)稍后将分配给该属性 python_object。 PyAnimal 将必须实现 trait 方法,并且该方法的实现将在 python_object 上调用该方法(PyAny 结构有一个 callmethod 方法,可以调用该对象的任何方法)。然后该 PyAnimal 对象将被传递给 make_three_sounds(&impl Animal a) 函数。所以 PyAnimal 的实现或多或少如下:

    struct PyAnimal {
        python_object: PyAny
    }
    
    impl Animal for PyAnimal {
       fn make_sound() {
           python_object.call_method('make_sound');
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-18
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      • 2011-03-31
      • 1970-01-01
      • 2020-03-14
      相关资源
      最近更新 更多