安装
git clone --depth=1 https://github.com/pybind/pybind11
cd pybind11
mkdir build
sudo make install
参考文档
https://pybind11.readthedocs.io/en/stable/basics.html
第一个简单示例
example.cpp
#include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
m.def("add", &add, "A function which adds two numbers");
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(example LANGUAGES CXX)
find_package(pybind11 REQUIRED)
include_directories(/usr/local/include)
pybind11_add_module(example example.cpp)
python
>>> import example
>>> example.add(3, 4)
>>> help(example)
添加默认参数
#include <pybind11/pybind11.h>
namespace py = pybind11;
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
m.def("add", &add, "A function which adds two numbers",
py::arg("i") = 1, py::arg("j") = 2 );
}
>>> import example
>>> example.add()
3
>>> example.add(j = 5)
6
以下代码效果相同
#include <pybind11/pybind11.h>
namespace py = pybind11;
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
using namespace pybind11::literals;
m.def("add", &add, "i"_a = 8, "j"_a = 10);
}
导出变量
PYBIND11_MODULE(example, m) {
m.attr("the_answer") = 42;
py::object world = py::cast("World");
m.attr("what") = world;
}
>>> import example
>>> example.the_answer
42
>>> example.what
'World'
类的使用
#include <pybind11/pybind11.h>
#include <string>
namespace py = pybind11;
struct Pet
{
Pet(const std::string &name):name(name){}
void setName(const std::string &name_)
{
name = name_;
}
const std::string &getName()
{
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);
}
>>> import example
>>> p = example.Pet("Molly")
>>> print(p)
<example.Pet object at 0x10e863ed8>
>>> p.getName()
'Molly'
>>> p.setName("Charly")
>>> p.getName()
'Charly'
修改类注释
PYBIND11_MODULE(example, m)
{
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 +"'>";
});
}
>>> import example
>>> p = example.Pet("Luccy")
>>> print(p)
<example.Pet named 'Luccy'>
导出类成员变量(public)
PYBIND11_MODULE(example, m)
{
using pybind11::literals::operator""_a;
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &>(), "name"_a = "liuyang2")
.def_readwrite("name", &Pet::name)
// .def("setName", &Pet::setName)
// .def("getName", &Pet::getName)
.def("__repr__",
[](const Pet &a) {
return "<example.Pet named '"+ a.name +"'>";
});
}
直接使用成员变量
>>> import example
>>> p = example.Pet("ly")
>>> p.name
'ly'
>>> p.name = "sxl"
>>> p.name
'sxl'
导出成员变量(private)
PYBIND11_MODULE(example, m)
{
using pybind11::literals::operator""_a;
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &>(), "name"_a = "liuyang2")
.def_property("name", &Pet::getName, &Pet::setName)
// .def_readwrite("name", &Pet::name)
// .def("setName", &Pet::setName)
// .def("getName", &Pet::getName)
.def("__repr__",
[](const Pet &a) {
return "<example.Pet named '"+ a.getName() +"'>";
});
}
设置成员变量只读属性
PYBIND11_MODULE(example, m)
{
using pybind11::literals::operator""_a;
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &>(), "name"_a = "liuyang2")
.def_property("name", &Pet::getName, nullptr)
//.def_readonly("name", &Pet::name) // 与上面等效
}
添加类的动态属性
以下代码会报错,Pet类中没有 age 属性
>>> p = example.Pet()
>>> p.name = 'Charly' # OK, attribute defined in C++
>>> p.age = 2 # fail
AttributeError: 'Pet' object has no attribute 'age'
Pet类支持动态属性,需要添加 py::dynamic_attr()
PYBIND11_MODULE(example, m)
{
using pybind11::literals::operator""_a;
py::class_<Pet>(m, "Pet", py::dynamic_attr())
.def(py::init<const std::string &>(), "name"_a = "liuyang")
.def_property("name", &Pet::getName, &Pet::setName);
}
现在可以正常运行
>>> p = example.Pet()
>>> p.name = 'Charly' # OK, overwrite value in C++
>>> p.age = 2 # OK, dynamically add a new attribute
>>> p.__dict__ # just like a native Python class
{'age': 2}
类的继承
#include <pybind11/pybind11.h>
#include <string>
namespace py = pybind11;
class Pet
{
public:
Pet() = default;
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;
};
class Dog: public Pet
{
public:
std::string bark()
{
return "woof!";
}
};
PYBIND11_MODULE(example, m)
{
using pybind11::literals::operator""_a;
py::class_<Pet>(m, "Pet", py::dynamic_attr())
.def(py::init<const std::string &>(), "name"_a = "liuyang")
.def_property("name", &Pet::getName, &Pet::setName);
//.def_property("name", &Pet::getName, nullptr); // 只读
py::class_<Dog, Pet>(m, "Dog")
.def(py::init<>())
.def("bark", &Dog::bark, "Dog bark sound");
}
以下写法等效
py::class_<Pet> pet(m, "Pet");
pet.def(py::init<const std::string &>())
.def_readwrite("name", &Pet::name);
// Method 2: pass parent class_ object:
py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
.def(py::init<>())
.def("bark", &Dog::bark);
类指针添加动态属性
添加以下代码
m.def("pet_store", [](){return std::unique_ptr<Pet>(new Dog("Molly"));});
在python中测试报错
>>> import example
>>> p = example.pet_store()
>>> p.bark()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'example.Pet' object has no attribute 'bark'
>>>
解决办法是在Pet中添加一个任意的虚函数,比如
virtual ~Pet() = default;
// 或者
// virtual void f(){}
>>> import example
>>> p = example.pet_store()
>>> p.bark()
'woof1!'
>>> type(p)
<class 'example.Dog'>
>>>
重载函数
#include <pybind11/pybind11.h>
namespace py = pybind11;
class Pet
{
public:
Pet(std::string name): name(name)
{}
void set(const std::string &name_)
{
name = name_;
}
void set(int age_)
{
age = age_;
}
const std::string& getName()
{
return name;
}
int age;
private:
std::string name;
};
PYBIND11_MODULE(example, m)
{
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &>())
.def_property("name", &Pet::getName, nullptr)
.def_readonly("age", &Pet::age)
.def("set", (void (Pet::*)(int)) &Pet::set)
.def("set", (void (Pet::*)(const std::string &)) &Pet::set);
}
或者可以这样写
PYBIND11_MODULE(example, m)
{
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &>())
.def_property("name", &Pet::getName, nullptr)
.def_readonly("age", &Pet::age)
.def("set", py::overload_cast<int>(&Pet::set))
.def("set", py::overload_cast<const std::string &>(&Pet::set));
// .def("set", (void (Pet::*)(int)) &Pet::set)
// .def("set", (void (Pet::*)(const std::string &)) &Pet::set);
}
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_));
枚举
#include <pybind11/pybind11.h>
namespace py = pybind11;
struct Pet
{
enum Kind {
Dog = 0,
Cat
};
Pet(const std::string &name , Kind type) : name(name), type(type)
{}
std::string name;
Kind type;
};
PYBIND11_MODULE(example, m)
{
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);
py::enum_<Pet::Kind>(pet, "Kind")
.value("Dog", Pet::Kind::Dog)
.value("Cat", Pet::Kind::Cat)
.export_values();
}
>>> import example
>>> p = example.Pet('Lucy', example.Pet.Cat)
>>> p.type
Kind.Cat