首页 > 其他分享 >pybind11绑定类(一)

pybind11绑定类(一)

时间:2023-06-24 17:11:57浏览次数:42  
标签:绑定 const name Pet py pybind11 class def

一、自定义数据结构-结构体

`class_`会创建C++ class或 struct的绑定。`init()`方法使用类构造函数的参数类型作为模板参数,并包装相应的构造函数;静态成员函数需要使用`class_::def_static`来绑定

#include <pybind11/pybind11.h>
namespace py = pybind11;

struct Pet {
    Pet(const std::string &name) : name(name) { }
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }

    std::string name;
};

PYBIND11_MODULE(example, m) {
    py::class_<Pet>(m, "Pet")
        .def(py::init<const std::string &>())
        .def("setName", &Pet::setName)
        .def("getName", &Pet::getName);
}

python
>>> import example
>>> p = example.Pet("Molly")
>>> print(p)
<example.Pet object at 0x10cd98060>
>>> p.getName()
u'Molly'
>>> p.setName("Charly")
>>> p.getName()
u'Charly'

 二、绑定匿名函数

使用`print(p)`打印对象信息时,上面的例子会得到一些基本无用的信息,可以绑定一个工具函数到`__repr__`方法,来返回可读性好的摘要信息。在不改变Pet类的基础上,使用一个匿名函数来完成。pybind11支持无状态和有状态的lambda闭包,即lambda表达式的`[]`是否带捕获参数。

py::class_<Pet>(m, "Pet")
    .def(py::init<const std::string &>())
    .def("setName", &Pet::setName)
    .def("getName", &Pet::getName)
    .def("__repr__",
        [](const Pet &a) {
            return "<example.Pet named '" + a.name + "'>";
        });

python
>>> print(p)
<example.Pet named 'Molly'>

三、访问成员变量

使用`class_::def_readwrite`方法可以导出公有成员变量,使用`class_::def_readonly`方法则可以导出只读成员。

py::class_<Pet>(m, "Pet")
    .def(py::init<const std::string &>())
    .def_readwrite("name", &Pet::name)

python
>>> p = example.Pet("Molly")
>>> p.name
u'Molly'
>>> p.name = "Charly"
>>> p.name
u'Charly'

假设`Pet::name`是一个私有成员变量,向外提供setter和getters方法。可以使用`class_::def_property()`(只读成员使用`class_::def_property_readonly()`)来定义并私有成员,并生成相应的setter和geter方法:

class Pet {
public:
    Pet(const std::string &name) : name(name) { }
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }
private:
    std::string name;
};

py::class_<Pet>(m, "Pet")
    .def(py::init<const std::string &>())
    .def_property("name", &Pet::getName, &Pet::setName)

四、动态属性

原生的Pyhton类可以动态地获取新属性:
```python
>>> class Pet:
... name = "Molly"
...
>>> p = Pet()
>>> p.name = "Charly" # overwrite existing
>>> p.age = 2 # dynamically add a new attribute
```

默认情况下,从C++导出的类不支持动态属性,其可写属性必须是通过`class_::def_readwrite`或`class_::def_property`定义的。试图设置其他属性将产生错误。要让C++类也支持动态属性,我们需要在`py::class_`的构造函数添加`py::dynamic_attr`标识:

py::class_<Pet>(m, "Pet", py::dynamic_attr())
    .def(py::init<>())
    .def_readwrite("name", &Pet::name);

五、继承与向下转型

 现在有两个具有继承关系的类:

struct Pet {
    Pet(const std::string &name) : name(name) { }
    std::string name;
};

struct Dog : Pet {
    Dog(const std::string &name) : Pet(name) { }
    std::string bark() const { return "woof!"; }
};

pybind11提供了两种方法来指明继承关系:1)将C++基类作为派生类`class_`的模板参数;2)将基类名作为`class_`的参数绑定到派生类。两种方法是等效的。

py::class_<Pet>(m, "Pet")
   .def(py::init<const std::string &>())
   .def_readwrite("name", &Pet::name);

// Method 1: template parameter:
py::class_<Dog, Pet /* <- specify C++ parent type */>(m, "Dog")
    .def(py::init<const std::string &>())
    .def("bark", &Dog::bark);

// Method 2: pass parent class_ object:
py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
    .def(py::init<const std::string &>())
    .def("bark", &Dog::bark);

六、多态类型

```c++
struct PolymorphicPet {
    virtual ~PolymorphicPet() = default;
};

struct PolymorphicDog : PolymorphicPet {
    std::string bark() const { return "woof!"; }
};

// Same binding code
py::class_<PolymorphicPet>(m, "PolymorphicPet");
py::class_<PolymorphicDog, PolymorphicPet>(m, "PolymorphicDog")
    .def(py::init<>())
    .def("bark", &PolymorphicDog::bark);

// Again, return a base pointer to a derived instance
m.def("pet_store2", []() { return std::unique_ptr<PolymorphicPet>(new PolymorphicDog); });
```

```python
>>> p = example.pet_store2()
>>> type(p)
PolymorphicDog  # automatically downcast
>>> p.bark()
u'woof!'
```

pybind11会自动地将一个指向多态基类的指针,向下转型为实际的派生类类型。不仅可以访问基类的虚函数,还能获取到通过基类看不到的,具体的派生类的方法和属性。

七、函数重载

重载方法即拥有相同的函数名,但入参不一样的函数:

struct Pet {
    Pet(const std::string &name, int age) : name(name), age(age) { }

    void set(int age_) { age = age_; }
    void set(const std::string &name_) { name = name_; }

    std::string name;
    int age;
};
py::class_<Pet>(m, "Pet")
   .def(py::init<const std::string &, int>())
   .def("set", static_cast<void (Pet::*)(int)>(&Pet::set), "Set the pet's age")
   .def("set", static_cast<void (Pet::*)(const std::string &)>(&Pet::set), "Set the pet's name");

如果你的编译器支持C++14,也可以使用下面的语法来转换重载函数:

py::class_<Pet>(m, "Pet")
    .def("set", py::overload_cast<int>(&Pet::set), "Set the pet's age")
    .def("set", py::overload_cast<const std::string &>(&Pet::set), "Set the pet's name");

`py::overload_cast`仅需指定函数类型,不用给出返回值类型,以避免原语法带来的不必要的干扰(`void (Pet::*)`)。如果是基于const的重载,需要使用`py::const`标识。

struct Widget {
    int foo(int x, float y);
    int foo(int x, float y) const;
};

py::class_<Widget>(m, "Widget")
   .def("foo_mutable", py::overload_cast<int, float>(&Widget::foo))
   .def("foo_const",   py::overload_cast<int, float>(&Widget::foo, py::const_));

如果你想在仅支持c++11的编译器上使用`py::overload_cast`语法,可以使用`py::detail::overload_cast_impl`来代替:

template <typename... Args>
using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;

py::class_<Pet>(m, "Pet")
    .def("set", overload_cast_<int>()(&Pet::set), "Set the pet's age")
    .def("set", overload_cast_<const std::string &>()(&Pet::set), "Set the pet's name");

八、枚举类型

现在有一个含有枚举和内部类型的类:

struct Pet {
    enum Kind {
        Dog = 0,
        Cat
    };

    struct Attributes {
        float age = 0;
    };

    Pet(const std::string &name, Kind type) : name(name), type(type) { }

    std::string name;
    Kind type;
    Attributes attr;
};


py::class_<Pet> pet(m, "Pet");

pet.def(py::init<const std::string &, Pet::Kind>())
    .def_readwrite("name", &Pet::name)
    .def_readwrite("type", &Pet::type)
    .def_readwrite("attr", &Pet::attr);

py::enum_<Pet::Kind>(pet, "Kind")
    .value("Dog", Pet::Kind::Dog)
    .value("Cat", Pet::Kind::Cat)
    .export_values();

py::class_<Pet::Attributes> attributes(pet, "Attributes")
    .def(py::init<>())
    .def_readwrite("age", &Pet::Attributes::age);

枚举类型的枚举项会被导出到类`__members__`属性中:

python
>>> Pet.Kind.__members__
{'Dog': Kind.Dog, 'Cat': Kind.Cat}

`name`属性可以返回枚举值的名称的unicode字符串,`str(enum)`也可以做到,但两者的实现目标不同。下面的例子展示了两者的差异:

python
>>> p = Pet("Lucy", Pet.Cat)
>>> pet_type = p.type
>>> pet_type
Pet.Cat
>>> str(pet_type)
'Pet.Cat'
>>> pet_type.name
'Cat'

Note: 当我们给`enum_`的构造函数增加`py::arithmetic()`标识时,pybind11将创建一个支持基本算术运算和位运算(如比较、或、异或、取反等)的枚举类型。

标签:绑定,const,name,Pet,py,pybind11,class,def
From: https://www.cnblogs.com/okmai77xue/p/17487285.html

相关文章

  • 如何将不同类型的Property绑定_使用绑定表达式
    如何将不同类型的Property绑定_使用绑定表达式我们知道,相同的Property可以直接调用bind进行绑定。而不同类型的Property则不能。现在,我想令textProperty和booleanProperty进行绑定:当booleanProperty为true或false时,同步修改textProperty.那么,有何方案?使用......
  • Vue(三):数据绑定(v-bind和v-model)
    数据绑定分为单向数据绑定和双向数据绑定,单向数据绑定就是前面学习的v-bind指令,而双向数据绑定则是下面学习的v-model指令。<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>数据绑定</title><scripttype="text/javascript&qu......
  • apache绑定于127.0.1.1
    Ubuntu下装Apache后,有时候,会绑定的地址为127.0.1.1。即提示信息:apache2:Couldnotreliablydeterminetheserver'sfullyqualifieddomainname,using127.0.1.1forServerName其实只要是127.开头的都一样,都是回环地址。你随便访问一个127.*都访问到的是本机。不过看起来......
  • 死信队列 - 死信交换机绑定配置【RabbitMQ】
    一、逻辑图二、死信交换机绑定配置1packagecn.itcast.mq.config;23importorg.springframework.amqp.core.*;4importorg.springframework.context.annotation.Bean;5importorg.springframework.context.annotation.Configuration;67importjava.util.H......
  • WinUI ComboBox加载时不能正常显示绑定属性
    搞WINUI时发现下述问题:ComboBox的item1绑定了一个属性,但是程序在加载完成后,页面上并不能正常显示(已经设置了默认选择为ComboBox绑定属性那个item,但是就不正常);而TextBlock绑定相同的属性,是能正常显示的。 具体现象如下,左红色框中为TextBlock,右蓝色框中为ComboBox。 其xam......
  • Vue2:怎么实现响应式双向绑定?
    一、vue2怎么实现双向绑定原理在Vue2中,双向绑定的实现是通过Vue2的响应式系统和数据绑定机制来完成的。下面是Vue2实现双向绑定的简要原理:数据劫持:当创建Vue实例时,Vue2会对data选项中的所有属性进行数据劫持。这通过使用Object.defineProperty()方法将每个属性转换为getter和s......
  • WPF 实现在Combobox下拉菜单展开,未选择,直接点击button自动收起下拉菜单,并响应button绑
    在正常情况下,下拉菜单展开后,我们都会选择一个合适的选项;但是在某些时候,展开下拉菜单后,发现并不需要选择一个选项,只是需要进行后续操作,然后这时在点击其他位置的button时,你会发现:只有combobox的下拉菜单收起来了,但是button的绑定事件并未响应…… 为了实现未选择下拉菜单,点击bu......
  • 一个执行计划异常变更的案例 - 外传之查看绑定变量值的几种方法
    这篇外传之前有这么几篇文章:《一个执行计划异常变更的案例-前传》《一个执行计划异常变更的案例-外传之绑定变量窥探》上一篇文章介绍了绑定变量以及11g之前绑定变量窥探的影响,这篇文章会介绍几种查看绑定变量值的方法。上篇文章我们说了,绑定变量实际是一些占位符,可以让仅......
  • 超多绑定变量导致异常的一个案例
    最近生产上出现一个问题,某个应用单个SQL中绑定变量个数超过了65535个,导致数据库出现了异常终止的现象。通过trace,看到很多这样的信息(为了脱敏,此处引用MOS的例子),导致问题的SQL诸如这种,BEGINUPDATETESTSETC1=:1,C2=:2,C3=:3,......
  • [pybind11]为c++项目写python API接口
    C++项目的pybind方法有哪些?有什么区别?以下是主要的python绑定cpp的方法:方法年份代表用户适用于CPython的C/C++扩展模块1991标准库PyBind11(推荐用于C++)2015Cython(推荐用于C)2007gevent、kivyHPy2019mypyc2017ctype2003oscryptocffi......