Skip to content

pybind11 cheatsheet documentation #1201

Open
@ezyang

Description

@ezyang

I have found the pybind11 documentation to be not so great for quickly trying to figure out "how the heck do I get from type A to type B". So I wrote my own notes. I'm interesting in getting these back into the official docs, but I am not sure what is the most appropriate form.

Here goes.


The important types:

  • py::handle - equivalent to PyObject* (no automatic refcounting)
  • py::object - does automatic refcounting. Subclass of py::handle.

Conversions

PyObject* ↔ py::handle

This is a trivial conversion. These two types are basically totally equivalent.

PyObject *x;

py::handle h = x; // implicit conversion OK
x = h.ptr(); // no implicit conversion to raw pointer

py::handle (or subclass) → py::object (or subclass)

The syntax here works for both py::object, and any of its subclasses (e.g., py::str, etc)
http://pybind11.readthedocs.io/en/stable/reference.html#_CPPv26object

All of these are unchecked. Do an isinstance check beforehand if necessary. (Note that if you try to do anything with the py::object subclass, pybind11 will probably throw an exception at that point, so you probably aren't completely hosed. But casts to py::foo things are not checked at the point you do the cast!)

Common gotcha: you MUST pass a template argument to py::cast if you're casting from a PyObject*, it will silently do the wrong thing if you don't.

py::handle h;

// Copying
auto o = py::reinterpret_borrow<py::object>(h); // h can be PyObject*
  // or
auto o = x.cast<py::object>();
  // or
auto o = py::cast<py::object>(h); // h can be PyObject*
// equivalent to:
//    Py_INCREF(x);
//    THPObjectPtr o(x);

// Moving
auto o = py::reinterpret_steal<py::object>(h); // h can be PyObject*
// equivalent to:
//    THPObjectPtr o(x);

py::object (or superclass) → py::handle

Stealing is pretty useful if you're trying to invoke a C API function that steals its argument.

py::object o;

// Borrows from o
py::handle h2 = o;
// refcount NOT increased; h2 is only live as long as o is

// Steals from o
py::handle h = o.release();
// o no longer valid

NB: a “copy” from object into handle doesn't make sense, because handle doesn't know how to manage its own memory.

NB2: these conversions are implemented by the implicit copy-constructor on py::handle,static casting the input py::object as a const py::handle& (in case you're like me and tried to find where in the code this conversion was implemented).

py::object → C++

py::handle h; // or py::object
CppType x = h.cast<CppType>(); // may throw cast_error
  // or
CppType x = py::cast<CppType>(h);
// x is a new copy unrelated to h

C++ → py::object

CppType x;

py::object o = py::cast(x);
  // or
py::object o = py::cast(x, return_value_policy::automatic);
// o is a new copy, but with a different policy it could be different

How do I...

// b = isinstance(x, ty)
py::handle x;
py::handle ty;
bool b = py::isinstance(x, ty);

// b = isinstance(x, str)
py::handle x;
bool b = py::isinstance<py::str>(x);

// b = isinstance(x, tuple)
py::handle x;
bool b = py::isinstance<py::tuple>(x);

// s = str(x)
py::handle x;
py::str s(x); // use the constructor

// b = hasattr(x, "something")
py::handle x;
bool b = py::hasattr(x, "something");

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions