Python PyO3-将扩展另一个类的类作为函数参数传递

Python PyO3-将扩展另一个类的类作为函数参数传递,python,inheritance,rust,traits,pyo3,Python,Inheritance,Rust,Traits,Pyo3,我在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 fo

我在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();
}

该库的用户可以使用structs Dog和Cat以及函数make_three_sounds。但他们也可以使用特征动物来定义自己的动物,然后将其传递给函数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]”。问题在于创建一个动物类,您可以扩展它,然后将其传递给函数make_three_sounds。为了创建Animal类,我可以创建一个使用Animal trait的结构,然后在上面添加“#[pyclass]”


但问题是:当Python库的用户扩展该类(动物)并将其传递给make_three_sounds时,它将不起作用,因为make_three_sounds必须接受实现trait Animal的结构,而Python对象不实现该trait(虽然它是一个类的对象,扩展了实现它的类/结构)。我可以制作一个接受PyAny对象的
make\u three\u sounds
函数的包装器,但是我以后如何将该对象传递给实际的
make\u three\u sounds
函数?

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

我创建了一个函数
make\u three\u sounds(PyAny a)
,该函数将作为一个包装,包装铁锈
make\u three\u sounds(&impl Animal a)
函数。该包装器将接受PyAny类型的对象。稍后我将执行以下操作。我将有一个特殊的结构PyAnimal实现trait Animal。该trait将有一个名为
python\u object
的属性。该PyAny对象来自python(表示类扩展Animal的对象)稍后将分配给该属性
python\u object
。PyAnimal必须实现trait方法,此方法的实现将在
python\u object
上调用该方法(PyAny struct有一个callmethod方法,可以调用该对象的任何方法)。然后,该PyAnimal对象将被传递到
发出三种声音(&impl Animal a)
函数。因此PyAnimal的实现大致如下:

struct PyAnimal {
    python_object: PyAny
}

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