+ #
+ Write C++ Bindings
+
+
+ #
+ Quick Start
+
+pkpy provides a pybind11 compatible layer which allows users to do convenient bindings.
+To begin with, use py::scoped_interpreter guard{}
to start the interpreter before using any Python objects.
+Or explicitly call py::interpreter::initialize()
and py::interpreter::finalize()
.
+ #
+ module
+
+#include <pybind11/pybind11.h>
+namespace py = pybind11;
+
+PYBIND11_EMBEDDED_MODULE(example, m) {
+ m.def("add", [](int a, int b) {
+ return a + b;
+ });
+
+ auto math = m.def_submodule("math");
+}
+
+ #
+ function
+
+int add(int a, int b) { return a + b; }
+
+int add(int a, int b, int c) { return a + b + c; }
+
+void register_function(py::module_& m)
+{
+ m.def("add", py::overload_cast<int, int>(&add));
+
+ // support function overload
+ m.def("add", py::overload_cast<int, int, int>(&add));
+
+ // bind with default arguments
+ m.def("sub", [](int a, int b) {
+ return a - b;
+ }, py::arg("a") = 1, py::arg("b") = 2);
+
+ // bind *args
+ m.def("add", [](py::args args) {
+ int sum = 0;
+ for (auto& arg : args) {
+ sum += arg.cast<int>();
+ }
+ return sum;
+ });
+
+ // bind **kwargs
+ m.def("add", [](py::kwargs kwargs) {
+ int sum = 0;
+ for (auto item : kwargs) {
+ sum += item.second.cast<int>();
+ }
+ return sum;
+ });
+}
+
+ #
+ class
+
+struct Point
+{
+ const int x;
+ int y;
+
+public:
+ Point() : x(0), y(0) {}
+
+ Point(int x, int y) : x(x), y(y) {}
+
+ Point(const Point& p) : x(p.x), y(p.y) {}
+
+ std::string stringfy() const {
+ return "(" + std::to_string(x) + ", " + std::to_string(y) + ")";
+ }
+};
+
+struct Point3D : Point
+{
+private:
+ int z;
+
+public:
+ Point3D(int x, int y, int z) : Point(x, y), z(z) {}
+
+ int get_z() const { return z; }
+
+ void set_z(int z) { this->z = z; }
+};
+
+void bind_class(py::module_& m)
+{
+ py::class_<Point>(m, "Point")
+ .def(py::init<>())
+ .def(py::init<int, int>())
+ .def(py::init<const Point&>())
+ .def_readonly("x", &Point::x)
+ .def_readwrite("y", &Point::y)
+ .def("__str__", &Point::stringfy);
+
+ // only support single inheritance
+ py::class_<Point3D, Point>(m, "Point3D", py::dynamic_attr())
+ .def(py::init<int, int, int>())
+ .def_property("z", &Point3D::get_z, &Point3D::set_z);
+
+ // dynamic_attr will enable the dict of bound class
+}
+
+ #
+ operators
+
+#include <pybind11/operators.h>
+namespace py = pybind11;
+
+struct Int {
+ int value;
+
+ Int(int value) : value(value) {}
+
+ Int operator+(const Int& other) const {
+ return Int(value + other.value);
+ }
+
+ Int operator-(const Int& other) const {
+ return Int(value - other.value);
+ }
+
+ bool operator==(const Int& other) const {
+ return value == other.value;
+ }
+
+ bool operator!=(const Int& other) const {
+ return value != other.value;
+ }
+};
+
+void bind_operators(py::module_& m)
+{
+ py::class_<Int>(m, "Int")
+ .def(py::init<int>())
+ .def(py::self + py::self)
+ .def(py::self - py::self)
+ .def(py::self == py::self)
+ .def(py::self != py::self);
+ // other operators are similar
+}
+
+ #
+ py::object
+
+py::object
is just simple wrapper around PyVar
. It supports some convenient methods to interact with Python objects.
here are some common methods:
+obj.attr("x"); // access attribute
+obj[1]; // access item
+
+obj.is_none(); // same as obj is None in Python
+obj.is(obj2); // same as obj is obj2 in Python
+
+// operators
+obj + obj2; // same as obj + obj2 in Python
+// ...
+obj == obj2; // same as obj == obj2 in Python
+// ...
+
+obj(...); // same as obj.__call__(...)
+
+py::cast(obj); // cast to Python object
+obj.cast<T>; // cast to C++ type
+
+py::type::of(obj); // get type of obj
+py::type::of<T>(); // get type of T, if T is registered
+you can also create some builtin objects with their according wrappers:
+py::bool_ b = {true};
+py::int_ i = {1};
+py::float_ f = {1.0};
+py::str s = {"hello"};
+py::list l = {1, 2, 3};
+py::tuple t = {1, 2, 3};
+// ...
+
+ #
+ More Examples
+
+More examples please see the test folder in the GSoC repository. All tested features are supported.
+
+ #
+ Limits and Comparison
+
+This is a feature list of pybind11 for pocketpy. It lists all completed and pending features. It also lists the features that cannot be implemented in the current version of pocketpy.
+
+ #
+ Function
+
+-
+
- Function overloading +
- Return value policy +
- is_prepend +
-
*args
and**kwargs
+ - Keep-alive +
- Call Guard +
- Default arguments +
- Keyword-Only arguments +
- Positional-Only arguments +
- Allow/Prohibiting None arguments +
+ #
+ Class
+
+-
+
- Creating bindings for a custom type +
- Binding lambda functions +
- Dynamic attributes +
- Inheritance and automatic downcasting +
- Enumerations and internal types +
- Instance and static fields +
++Binding static fields may never be implemented in pocketpy because it requires a metaclass, which is a heavy and infrequently used feature.
+
+ #
+ Exceptions
+
+Need further discussion.
+
+ #
+ Smart pointers
+
+-
+
- std::shared_ptr +
- std::unique_ptr +
- Custom smart pointers +
+ #
+ Type conversions
+
+-
+
- Python built-in types +
- STL Containers +
- Functional +
- Chrono +
+ #
+ Python C++ interface
+
+Need further discussion.
+-
+
-
object
+ -
none
+ -
type
+ -
bool_
+ -
int_
+ -
float_
+ -
str
+ -
bytes
+ -
bytearray
+ -
tuple
+ -
list
+ -
set
+ -
dict
+ -
slice
+ -
iterable
+ -
iterator
+ -
function
+ -
buffer
+ -
memoryview
+ -
capsule
+
+ #
+ Miscellaneous
+
+-
+
- Global Interpreter Lock (GIL) +
- Binding sequence data types, iterators, the slicing protocol, etc. +
- Convenient operators binding +
+ #
+ Differences between CPython and pocketpy
+
+-
+
only
+add
,sub
andmul
have corresponding right versions in pocketpy. So if you bindint() >> py::self
, it will has no effect in pocketpy.
+
+__new__
and__del__
are not supported in pocketpy.
+in-place operators, such as
++=
,-=
,*=
, etc., are not supported in pocketpy.
+the return value of
+globals
is immutable in pocketpy.
+