C++ API Reference (Core)¶
Macros¶
-
NB_MODULE(name, variable)¶
This macro creates the entry point that will be invoked when the Python interpreter imports an extension module. The module name is given as the first argument and it should not be in quotes. It must match the module name given to the
nanobind_add_module()
function in the CMake build system.The second macro argument defines a variable of type
module_
. The body of the declaration typically contains a sequence of operations that populate the module variable with contents.NB_MODULE(example, m) { m.doc() = "Example module"; // Add bindings here m.def("add", []() { return "Hello, World!"; }); }
-
NB_MAKE_OPAQUE(T)¶
The macro registers a partial template specialization pattern for the type
T
that marks it as opaque, meaning that nanobind won’t try to run its type casting template machinery on it.This is useful when trying to register a binding for
T
that is simultaneously also covered by an existing type caster.This macro should be used at the top level (outside of namespaces and program code).
Python object API¶
Nanobind ships with a wide range of Python wrapper classes like
object
, list
, etc. Besides class-specific operations
(e.g., list::append()
), these classes also implement core operations
that can be performed on any Python object. Since it would be tedious to
implement this functionality over and over again, it is realized by the
following mixin class that lives in the nanobind::detail
namespace.
-
template<typename Derived>
class api¶ This mixin class adds common functionality to various nanobind types using the curiously recurring template pattern (CRTP). The only requirement for the
Derived
template parameter is that it implements the member functionPyObject *ptr() const
that gives access to the underlying Python object pointer.-
iterator begin() const¶
Return a forward iterator analogous to
iter()
in Python. The object must be a collection that supports the iteration protocol. This interface provides a generic iterator that works any type of Python object. Thetuple
,list
, anddict
wrappers provide more efficient specialized alternatives.
-
detail::accessor<obj_attr> attr(handle key) const¶
Analogous to
self.key
in Python, wherekey
is a Python object. The result is wrapped in anaccessor
so that it can be read and written.
-
detail::accessor<str_attr> attr(const char *key) const¶
Analogous to
self.key
in Python, wherekey
is a C-style string. The result is wrapped in anaccessor
so that it can be read and written.
-
detail::accessor<str_attr> doc() const¶
Analogous to
self.__doc__
. The result is wrapped in anaccessor
so that it can be read and written.
-
detail::accessor<obj_item> operator[](handle key) const¶
Analogous to
self[key]
in Python, wherekey
is a Python object. The result is wrapped in anaccessor
so that it can be read and written.
-
detail::accessor<str_item> operator[](const char *key) const¶
Analogous to
self[key]
in Python, wherekey
is a C-style string. The result is wrapped in anaccessor
so that it can be read and written.
-
template<typename T, enable_if_t<std::is_arithmetic_v<T>> = 1>
detail::accessor<num_item> operator[](T key) const¶ Analogous to
self[key]
in Python, wherekey
is an arithmetic type (e.g., an integer). The result is wrapped in anaccessor
so that it can be read and written.
-
template<rv_policy policy = rv_policy::automatic_reference, typename ...Args>
object operator()(Args&&... args) const¶ Assuming the Python object is a function or implements the
__call__
protocol,operator()()
invokes the underlying function, passing an arbitrary set of parameters, while expanding any detected variable length argument and keyword argument packs. The result is returned as anobject
and may need to be converted back into a Python object usingcast()
.Type conversion is performed using the return value policy
policy
When type conversion of arguments or return value fails, the function raises a
cast_error
. When the Python function call fails, it instead raises apython_error
.
-
args_proxy operator*() const¶
Given a a tuple or list, this helper function performs variable argument list unpacking in function calls resembling the
*
operator in Python. Applyingoperator*()
twice yields**
keyword argument unpacking for dictionaries.
-
bool is_none() const¶
Analogous to
self is None
in Python.
-
bool is_type() const¶
Analogous to
isinstance(self, type)
in Python.
-
bool is_valid() const¶
Checks if this wrapper contains a valid Python object (in the sense that the
PyObject *
pointer is non-null).
-
template<typename T>
object operator+=(const api<T> &other)¶ Equivalent to
self += other
in Python. Note that theapi
version of the in-place operator does not update theself
reference, which may lead to unexpected results when working with immutable types that return their result instead of updatingself
.The
object
class and subclasses override the in-place operators to achieve more intuitive behavior.
-
template<typename T>
object operator-=(const api<T> &other)¶ Equivalent to
self -= other
in Python. Seeoperator+=()
for limitations.
-
template<typename T>
object operator*=(const api<T> &other)¶ Equivalent to
self *= other
in Python. Seeoperator+=()
for limitations.
-
template<typename T>
object operator/=(const api<T> &other)¶ Equivalent to
self /= other
in Python. Seeoperator+=()
for limitations.
-
template<typename T>
object operator|=(const api<T> &other)¶ Equivalent to
self |= other
in Python. Seeoperator+=()
for limitations.
-
template<typename T>
object operator&=(const api<T> &other)¶ Equivalent to
self &= other
in Python. Seeoperator+=()
for limitations.
-
template<typename T>
object operator^=(const api<T> &other)¶ Equivalent to
self ^= other
in Python. Seeoperator+=()
for limitations.
-
template<typename T>
object operator<<=(const api<T> &other)¶ Equivalent to
self <<= other
in Python. Seeoperator+=()
for limitations.
-
template<typename T>
object operator>>=(const api<T> &other)¶ Equivalent to
self >>= other
in Python. Seeoperator+=()
for limitations.
-
iterator begin() const¶
-
template<typename Impl>
class accessor¶ This helper class facilitates attribute and item access. Casting an
accessor
to ahandle
orobject
subclass causes a corresponding call to__getitem__
or__getattr__
depending on the template argumentImpl
. Assigning ahandle
orobject
subclass causes a call to__setitem__
or__setattr__
.
Handles and objects¶
nanobind provides two styles of Python object wrappers: classes without
reference counting deriving from handle
, and reference-counted
wrappers deriving from object
. Reference counting bugs can be
really tricky to track down, hence it is recommended that you always prefer
object
-style wrappers unless there are specific reasons that
warrant the use of raw handles.
Without reference counting¶
-
class handle : public detail::api<handle>¶
This class provides a thin wrapper around a raw
PyObject *
pointer. Its main purpose is to intercept various C++ operations and convert them into Python C API calls. It does not do any reference counting and can be somewhat unsafe to use.-
handle() = default¶
Default constructor. Creates an invalid handle wrapping a null pointer. (
detail::api::is_valid()
isfalse
)
-
handle(const PyObject *o)¶
Initialize a handle from a Python object pointer. Does not change the reference count of
o
.
-
handle(const PyTypeObject *o)¶
Initialize a handle from a Python type object pointer. Does not change the reference count of
o
.
-
explicit operator bool() const¶
Check if the handle refers to a valid Python object. Equivalent to
detail::api::is_valid()
-
handle inc_ref() const noexcept¶
Increases the reference count and returns a reference to the Python object. Never raises an exception.
-
handle dec_ref() const noexcept¶
Decreases the reference count and returns a reference to the Python object. Never raises an exception.
-
PyObject *ptr() const¶
Return the underlying
PyObject*
pointer.
-
handle() = default¶
With reference counting¶
-
class object : public handle¶
This class provides a convenient RAII wrapper around a
PyObject*
pointer. Likehandle
, it intercepts various C++ operations and converts them into Python C API calls.The main difference to
handle
is that it uses reference counting to keep the underlying Python object alive.Use the
borrow()
andsteal()
functions to create anobject
from ahandle
orPyObject*
pointer.-
object() = default¶
Default constructor. Creates an invalid object wrapping a null pointer. (
detail::api::is_valid()
isfalse
)
-
object(object &&o)¶
Move constructor. Steals the object from
o
without changing its reference count.
-
~object()¶
Decrease the reference count of the referenced Python object (if valid).
-
object &operator=(object &&o)¶
Move assignment operator. Decreases the reference count of the currently held object (if valid) and steals the object from
o
without changing its reference count.
-
object &operator=(const object &o)¶
Copy assignment operator. Decreases the reference count of the currently held object (if valid) and acquires a new reference to the object
o
(if valid).
-
void reset()¶
Decreases the reference count of the currently held object (if valid) and resets the internal pointer to
nullptr
.
-
handle release()¶
Resets the internal pointer to
nullptr
and returns its previous contents as ahandle
. This operation does not change the object’s reference count and should be used carefully.
-
object() = default¶
-
template<typename T = object>
T borrow(handle h)¶ Create a reference-counted Python object wrapper of type
T
from a raw handle orPyObject *
pointer. The target typeT
must beobject
(the default) or one of its derived classes. The function does not perform any conversions or checks—it is up to the user to make sure that the target type is correct.The function borrows a reference, which means that it will increase the reference count while constructing
T
.For example, consider the Python C API function PyList_GetItem(), whose documentation states that it returns a borrowed reference. An interface between this API and nanobind could look as follows:
PyObject* list = ...; Py_ssize_t index = ...; nb::object o = nb::borrow(PyList_GetItem(obj, index));
Using
steal()
in this setting is incorrect and would lead to a reference underflow.
-
template<typename T = object>
T steal(handle h)¶ Create a reference-counted Python object wrapper of type
T
from a raw handle orPyObject *
pointer. The target typeT
must beobject
(the default) or one of its derived classes. The function does not perform any conversions or checks—it is up to the user to make sure that the target type is correct.The function steals a reference, which means that constructing
T
leaves the object’s reference count unchanged.For example, consider the Python C API function PyObject_Str(), whose documentation states that it returns a new reference. An interface between this API and nanobind could look as follows:
PyObject* value = ...; nb::object o = nb::steal(PyObject_Str(value));
Using
borrow()
in this setting is incorrect and would lead to a reference leak.
Attribute access¶
-
bool hasattr(handle h, const char *key) noexcept¶
Check if the given object has an attribute string
key
. The function never raises an exception and returnsfalse
in case of an internal error.Equivalent to
hasattr(h, key)
in Python.
-
bool hasattr(handle h, handle key) noexcept¶
Check if the given object has a attribute represented by the Python object
key
. The function never raises an exception and returnsfalse
in case of an internal error.Equivalent to
hasattr(h, key)
in Python.
-
object getattr(handle h, const char *key)¶
Equivalent to
h.key
andgetattr(h, key)
in Python. Raisespython_error
if the operation fails.
-
object getattr(handle h, handle key)¶
Equivalent to
h.key
andgetattr(h, key)
in Python. Raisespython_error
if the operation fails.
-
object getattr(handle h, const char *key, handle def) noexcept¶
Equivalent to
getattr(h, key, def)
in Python. Never raises an exception and returnsdef
when the operation fails, or when the desired attribute could not be found.
-
object getattr(handle h, handle key, handle def) noexcept¶
Equivalent to
getattr(h, key, def)
in Python. Never raises an exception and returnsdef
when the operation fails, or when the desired attribute could not be found.
-
void setattr(handle h, const char *key, handle value)¶
Equivalent to
h.key = value
andsetattr(h, key, value)
in Python. Raisespython_error
if the operation fails.
-
void setattr(handle h, handle key, handle value)¶
Equivalent to
h.key = value
andsetattr(h, key, value)
in Python. Raisespython_error
if the operation fails.
-
void delattr(handle h, const char *key)¶
Equivalent to
del h.key
anddelattr(h, key)
in Python. Raisespython_error
if the operation fails.
-
void delattr(handle h, handle key)¶
Equivalent to
del h.key
anddelattr(h, key)
in Python. Raisespython_error
if the operation fails.
-
template<typename T>
void del(detail::accessor<T>&)¶ Remove an element from a sequence or mapping. The C++ statement
nb::del(o[key]);
is equivalent to
del o[key]
in Python.When the element cannot be removed, the function will raise
python_error
wrapping either a PythonIndexError
(for sequence types) or aKeyError
(for mapping types).
Size queries¶
-
size_t len(handle h)¶
Equivalent to
len(h)
in Python. Raisespython_error
if the operation fails.
-
size_t len_hint(handle h)¶
Equivalent to
operator.length_hint(h)
in Python. Raisespython_error
if the operation fails.
Type queries¶
-
template<typename T>
isinstance(handle h)¶ Checks if the Python object
h
represents a valid instance of the C++ typeT
. This works for bound C++ classes, basic types (int
,bool
, etc.), and Python type wrappers (list
,dict
,module_
, etc.).Note: the check even works when
T
involves a type caster (e.g., an STL types likestd::vector<float>
). However, this involve a wasteful attempt to convert the object to C++. It may be more efficient to just perform the conversion usingcast()
and catch potential raised exceptions.
-
isinstance(handle inst, handle cls)¶
Checks if the Python object
inst
is an instance of the Python typecls
.
-
template<typename T>
handle type() noexcept¶ Returns the Python type object associated with the C++ type
T
. When the type not been bound via nanobind, the function returns an invalid handle (detail::api::is_valid()
isfalse
).Note: in contrast to the
isinstance()
function above, builtin types, type wrappers, and types handled using type casters, are not supported.
Wrapper classes¶
-
class tuple : public object¶
Wrapper class representing Python
tuple
instances.Use the standard
operator[]
C++ operator with an integer argument to read tuple elements (the bindings for this operator are provided by the parent class and not listed here). Once created, the set is immutable and its elements cannot be replaced.Use the
make_tuple()
function to create new tuples.-
tuple()¶
Create an empty tuple
-
tuple(handle h)¶
Attempt to convert a given Python object into a tuple. Analogous to the expression
tuple(h)
in Python.
-
size_t size() const¶
Return the number of tuple elements.
-
detail::fast_iterator begin() const¶
Return a forward iterator analogous to
iter()
in Python. The function overrides a generic version indetail::api
and is more efficient for tuples.
-
detail::fast_iterator end() const¶
Return a sentinel that ends the iteration.
-
template<typename T, enable_if_t<std::is_arithmetic_v<T>> = 1>
detail::accessor<num_item_tuple> operator[](T key) const¶ Analogous to
self[key]
in Python, wherekey
is an arithmetic type (e.g., an integer). The result is wrapped in anaccessor
so that it can be read and converted. Write access is not possible.The function overrides the generic version in
detail::api
and is more efficient for tuples.
-
tuple()¶
-
class list : public object¶
Wrapper class representing Python
list
instances.Use the standard
operator[]
C++ operator with an integer argument to read and write list elements (the bindings for this operator are provided by the parent class and not listed here).Use the
nb::del
function to remove elements.-
list()¶
Create an empty list
-
list(handle h)¶
Attempt to convert a given Python object into a list. Analogous to the expression
list(h)
in Python.
-
size_t size() const¶
Return the number of list elements.
-
template<typename T>
void append(T &&value)¶ Append an element to the list. When
T
does not already represent a wrapped Python object, the function performs a cast.
-
template<typename T>
void insert(Py_ssize_t index, T &&value)¶ Insert an element to the list (at index
index
, which may also be negative). WhenT
does not already represent a wrapped Python object, the function performs a cast.
-
void clear()¶
Clear the list entries.
-
void sort()¶
Analogous to the
.sort()
method oflist
in Python.
-
void reverse()¶
Analogous to the
.reverse()
method oflist
in Python.
-
template<typename T, enable_if_t<std::is_arithmetic_v<T>> = 1>
detail::accessor<num_item_list> operator[](T key) const¶ Analogous to
self[key]
in Python, wherekey
is an arithmetic type (e.g., an integer). The result is wrapped in anaccessor
so that it can be read and written.The function overrides the generic version in
detail::api
and is more efficient for lists.
-
detail::fast_iterator begin() const¶
Return a forward iterator analogous to
iter()
in Python. The operator provided here overrides the generic version indetail::api
and is more efficient for lists.
-
detail::fast_iterator end() const¶
Return a sentinel that ends the iteration.
-
list()¶
-
class dict : public object¶
Wrapper class representing Python
dict
instances.Use the standard
operator[]
C++ operator to read and write dictionary elements (the bindings for this operator are provided by the parent class and not listed here).Use the
nb::del
function to remove elements.-
dict()¶
Create an empty dictionary
-
size_t size() const¶
Return the number of dictionary elements.
-
template<typename T>
bool contains(T &&key) const¶ Check whether the dictionary contains a particular key. When
T
does not already represent a wrapped Python object, the function performs a cast.
-
detail::dict_iterator begin() const¶
Return an item iterator that returns
std::pair<handle, handle>
key-value pairs analogous toiter(dict.items())
in Python.In free-threaded Python, the :cpp:class:
detail::dict_iterator
class acquires a lock to the underlying dictionary to enable the use of the efficient but thread-unsafePyDict_Next()
Python C traversal routine.
-
detail::dict_iterator end() const¶
Return a sentinel that ends the iteration.
-
void clear()¶
Clear the contents of the dictionary.
-
dict()¶
-
class set : public object¶
Wrapper class representing Python
set
instances.-
set()¶
Create an empty set
-
set(handle h)¶
Attempt to convert a given Python object into a set. Analogous to the expression
set(h)
in Python.
-
size_t size() const¶
Return the number of set elements.
-
template<typename T>
void add(T &&key)¶ Add a key to the set. When
T
does not already represent a wrapped Python object, the function performs a cast.
-
template<typename T>
bool contains(T &&key) const¶ Check whether the set contains a particular key. When
T
does not already represent a wrapped Python object, the function performs a cast.
-
void clear()¶
Clear the contents of the set.
-
set()¶
-
class module_ : public object¶
Wrapper class representing Python
module
instances. The underscore at the end disambiguates the class name from the C++20module
declaration.-
template<typename Func, typename ...Extra>
module_ &def(const char *name, Func &&f, const Extra&... extra)¶ Bind the function
f
to the identifiername
within the module. Returns a reference to*this
so that longer sequences of binding declarations can be chained, as inm.def(...).def(...);
. The variable lengthextra
parameter can be used to pass docstrings and other function binding annotations.Example syntax:
void test() { printf("Hello world!"); } NB_MODULE(example, m) { // here, "m" is variable of type 'module_'. m.def("test", &test, "A test function") .def(...); // more binding declarations }
-
module_ import_(const char *name)¶
Import the Python module with the specified name and return a reference to it. The underscore at the end disambiguates the function name from the C++20
import
statement.Example usage:
nb::module_ np = nb::module_::import_("numpy"); nb::object np_array = np.attr("array");
-
module_ import_(handle name)¶
Import the Python module with the specified name and return a reference to it. In contrast to the version above, this function expects a Python object as key.
-
module_ def_submodule(const char *name, const char *doc = nullptr)¶
Create a Python submodule within an existing module and return a reference to it. Can be chained recursively.
Example usage:
NB_MODULE(example, m) { nb::module_ m2 = m.def_submodule("sub", "A submodule of 'example'"); nb::module_ m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); }
-
template<typename Func, typename ...Extra>
-
class capsule : public object¶
Capsules are small opaque Python objects that wrap a C or C++ pointer and a cleanup routine.
-
capsule(const void *ptr, void (*cleanup)(void*) noexcept = nullptr)¶
Construct an unnamed capsule wrapping the pointer
p
. When the capsule is garbage collected, Python will call the destructorcleanup
(if provided) with the value ofp
.
-
capsule(const void *ptr, const char *name, void (*cleanup)(void*) noexcept = nullptr)¶
Construct a named capsule with name
name
wrapping the pointerp
. When the capsule is garbage collected, Python will call the destructorcleanup
(if provided) with the value ofp
.
-
const char *name() const¶
Return the capsule name (or
nullptr
when the capsule is unnamed)
-
void *data() const¶
Return the pointer wrapped by the capsule.
-
capsule(const void *ptr, void (*cleanup)(void*) noexcept = nullptr)¶
-
class bool_ : public object¶
This wrapper class represents Python
bool
instances.-
bool_(handle h)¶
Performs a boolean cast within Python. This is equivalent to the Python expression
bool(h)
.
-
explicit bool_(bool value)¶
Convert an C++ boolean instance into a Python
bool
.
-
explicit operator bool() const¶
Extract the boolean value underlying this object.
-
bool_(handle h)¶
-
class int_ : public object¶
This wrapper class represents Python
int
instances. It can handle large numbers requiring more than 64 bits of storage.-
int_(handle h)¶
Performs an integer cast within Python. This is equivalent to the Python expression
int(h)
.
-
int_(handle h)¶
-
class float_ : public object¶
This wrapper class represents Python
float
instances.-
float_(handle h)¶
Performs an floating point cast within Python. This is equivalent to the Python expression
float(h)
.
-
explicit float_(double value)¶
Convert an C++ double value into a Python float objecct
-
explicit operator double() const¶
Convert a Python float object into a C++ double value
-
float_(handle h)¶
-
class str : public object¶
This wrapper class represents Python unicode
str
instances.-
str(handle h)¶
Performs a string cast within Python. This is equivalent equivalent to the Python expression
str(h)
.
-
str(const char *s)¶
Convert a null-terminated C-style string in UTF-8 encoding into a Python string.
-
str(const char *s, size_t n)¶
Convert a C-style string in UTF-8 encoding of length
n
bytes into a Python string.
-
str(handle h)¶
-
class bytes : public object¶
This wrapper class represents Python unicode
bytes
instances.-
bytes(handle h)¶
Performs a cast within Python. This is equivalent to the Python expression
bytes(h)
.
-
bytes(const char *s)¶
Convert a null-terminated C-style string encoding into a Python
bytes
object.
-
bytes(const void *buf, size_t n)¶
Convert a byte buffer
buf
of lengthn
bytes into a Pythonbytes
object. The buffer can contain embedded null bytes.
-
const char *c_str() const¶
Convert a Python bytes object into a null-terminated C-style string.
-
size_t size() const¶
Return the size in bytes.
-
const void *data() const¶
Convert a Python
bytes
object into a byte buffer of lengthbytes::size()
bytes.
-
bytes(handle h)¶
-
class bytearray : public object¶
This wrapper class represents Python
bytearray
instances.-
bytearray()¶
Create an empty
bytearray
.
-
bytearray(handle h)¶
Performs a cast within Python. This is equivalent to the Python expression
bytearray(h)
.
-
bytearray(const void *buf, size_t n)¶
Convert a byte buffer
buf
of lengthn
bytes into a Pythonbytearray
object. The buffer can contain embedded null bytes.
-
const char *c_str() const¶
Convert a Python
bytearray
object into a null-terminated C-style string.
-
size_t size() const¶
Return the size in bytes.
-
void *data()¶
Convert a Python
bytearray
object into a byte buffer of lengthbytearray::size()
bytes.
-
const void *data() const¶
Convert a Python
bytearray
object into a byte buffer of lengthbytearray::size()
bytes.
-
void resize(size_t n)¶
Resize the internal buffer of a Python
bytearray
object ton
. Any space added by this method, which callsPyByteArray_Resize
, will not be initialized and may contain random data.
-
bytearray()¶
-
class mapping : public object¶
Wrapper class representing arbitrary Python mapping types.
-
class iterator : public object¶
Wrapper class representing a Python iterator.
-
class iterable : public object¶
Wrapper class representing an object that can be iterated upon (in the sense that calling
iter()
is valid).
-
class slice : public object¶
Wrapper class representing a Python slice object.
-
slice(handle start, handle stop, handle step)¶
Create the slice object given by
slice(start, stop, step)
in Python.
-
template<typename T, detail::enable_if_t<std::is_arithmetic_v<T>> = 0>
slice(T stop)¶ Create the slice object
slice(stop)
, wherestop
is represented by a C++ integer type.
-
template<typename T, detail::enable_if_t<std::is_arithmetic_v<T>> = 0>
slice(T start, T stop)¶ Create the slice object
slice(start, stop)
, wherestart
andstop
are represented by a C++ integer type.
-
slice(handle start, handle stop, handle step)¶
-
class ellipsis : public object¶
Wrapper class representing a Python ellipsis (
...
) object.-
ellipsis()¶
Create a wrapper referencing the unique Python
Ellipsis
object.
-
ellipsis()¶
-
class not_implemented : public object¶
Wrapper class representing a Python
NotImplemented
object.-
not_implemented()¶
Create a wrapper referencing the unique Python
NotImplemented
object.
-
not_implemented()¶
-
class args : public tuple¶
Variable argument keyword list for use in function argument declarations.
Parameterized wrapper classes¶
-
template<typename T>
class handle_t : public handle¶ Wrapper class representing a handle to a subclass of the C++ type
T
. It can be used to bind functions that take the associated Python object in its wrapped form, while rejecting objects with a different type (i.e., it is more discerning thanhandle
, which accepts any Python object).// Bind the class A class A { int value; }; nb::class_<A>(m, "A"); // Bind a function that takes a Python object representing a 'A' instance m.def("process_a", [](nb::handle_t<A> h) { PyObject * a_py = h.ptr(); // PyObject* pointer to wrapper A &a_cpp = nb::cast<A &>(h); // Reference to C++ instance });
-
template<typename T>
class type_object_t : public type_object¶ Wrapper class representing a Python type object that is a subtype of the C++ type
T
. It can be used to bind functions that only accept type objects satisfying this criterion (i.e., it is more discerning thantype_object
, which accepts any Python type object).
Error management¶
nanobind provides a range of functionality to convert C++ exceptions into
equivalent Python exceptions and raise captured Python error state in C++. The
exception
class is also relevant in this context, but is listed in
the reference section on class binding.
-
struct error_scope¶
RAII helper class that temporarily stashes any existing Python error status. This is important when running Python code in the context of an existing failure that must be processed (e.g., to generate an error message).
-
error_scope()¶
Stash the current error status (if any)
-
~error_scope()¶
Restore the stashed error status (if any)
-
error_scope()¶
-
struct python_error : public std::exception¶
Exception that represents a detected Python error status.
-
python_error()¶
This constructor may only be called when a Python error has occurred (
PyErr_Occurred()
must betrue
). It creates a C++ exception object that represents this error and clears the Python error status.
-
python_error(const python_error&)¶
Copy constructor
-
python_error(python_error&&) noexcept¶
Move constructor
-
const char *what() noexcept¶
Return a stringified version of the exception. nanobind internally normalizes the exception and generates a traceback that is included as part of this string. This can be a relatively costly operation and should only be used if all of this detail is actually needed.
-
bool matches(handle exc) noexcept¶
Checks whether the exception has the same type as
exc
.The argument to this function is usually one of the Standard Exceptions.
-
void restore() noexcept¶
Restore the error status in Python and clear the
python_error
contents. This may only be called once, and you should not reraise thepython_error
in C++ afterward.
-
void discard_as_unraisable(handle context) noexcept¶
Pass the error to Python’s
sys.unraisablehook()
, which prints a traceback tosys.stderr
by default but may be overridden. Likerestore()
, this consumes the error and you should not reraise the exception in C++ afterward.The context argument should be some object whose
repr()
helps identify the location of the error. The defaultsys.unraisablehook()
prints a traceback that begins with the textException ignored in:
followed by the result ofrepr(context)
.Example use case: handling a Python error that occurs in a C++ destructor where you cannot raise a C++ exception.
-
void discard_as_unraisable(const char *context) noexcept¶
Convenience wrapper around the above function, which takes a C-style string for the
context
argument.
-
python_error()¶
-
class cast_error¶
The function
cast()
raises this exception to indicate that a cast was unsuccessful.-
cast_error()¶
Constructor
-
cast_error()¶
-
class next_overload¶
Raising this special exception from a bound function informs nanobind that the function overload detected incompatible inputs. nanobind will then try other overloads before reporting a
TypeError
.This feature is useful when a multiple overloads of a function accept overlapping or identical input types (e.g.
object
) and must run code at runtime to select the right overload.You should probably write a thorough docstring that explicitly mentions the expected inputs in this case, since the behavior won’t be obvious from the auto-generated function signature. It can be frustrating when a function call fails with an error message stating that the provided arguments aren’t compatible with any overload, when the associated error message suggests otherwise.
-
next_overload()¶
Constructor
-
next_overload()¶
-
class builtin_exception : public std::runtime_error¶
General-purpose class to propagate builtin Python exceptions from C++. A number of convenience functions (see below) instantiate it.
-
builtin_exception stop_iteration(const char *what = nullptr)¶
Convenience wrapper to create a
builtin_exception
C++ exception instance that nanobind will re-raise as a PythonStopIteration
exception when it crosses the C++ ↔ Python interface.
-
builtin_exception index_error(const char *what = nullptr)¶
Convenience wrapper to create a
builtin_exception
C++ exception instance that nanobind will re-raise as a PythonIndexError
exception when it crosses the C++ ↔ Python interface.
-
builtin_exception key_error(const char *what = nullptr)¶
Convenience wrapper to create a
builtin_exception
C++ exception instance that nanobind will re-raise as a PythonKeyError
exception when it crosses the C++ ↔ Python interface.
-
builtin_exception value_error(const char *what = nullptr)¶
Convenience wrapper to create a
builtin_exception
C++ exception instance that nanobind will re-raise as a PythonValueError
exception when it crosses the C++ ↔ Python interface.
-
builtin_exception type_error(const char *what = nullptr)¶
Convenience wrapper to create a
builtin_exception
C++ exception instance that nanobind will re-raise as a PythonTypeError
exception when it crosses the C++ ↔ Python interface.
-
builtin_exception buffer_error(const char *what = nullptr)¶
Convenience wrapper to create a
builtin_exception
C++ exception instance that nanobind will re-raise as a PythonBufferError
exception when it crosses the C++ ↔ Python interface.
-
builtin_exception import_error(const char *what = nullptr)¶
Convenience wrapper to create a
builtin_exception
C++ exception instance that nanobind will re-raise as a PythonImportError
exception when it crosses the C++ ↔ Python interface.
-
builtin_exception attribute_error(const char *what = nullptr)¶
Convenience wrapper to create a
builtin_exception
C++ exception instance that nanobind will re-raise as a PythonAttributeError
exception when it crosses the C++ ↔ Python interface.
-
void register_exception_translator(void (*exception_translator)(const std::exception_ptr&, void*), void *payload = nullptr)¶
Install an exception translator callback that will be invoked whenever nanobind’s function call dispatcher catches a previously unknown C++ exception. This exception translator should follow a standard structure of re-throwing an exception, catching a specific type, and converting this into a Python error status upon “success”.
Here is an example for a hypothetical
ZeroDivisionException
.register_exception_translator( [](const std::exception_ptr &p, void * /*payload*/) { try { std::rethrow_exception(p); } catch (const ZeroDivisionException &e) { PyErr_SetString(PyExc_ZeroDivisionError, e.what()); } }, nullptr /*payload*/);
Generally, you will want to use the more convenient exception binding interface provided by
exception
class. This function provides an escape hatch for more specialized use cases.
-
void chain_error(handle type, const char *fmt, ...) noexcept¶
Raise a Python error of type
type
using the format stringfmt
interpreted byPyErr_FormatV
.If a Python error state was already set prior to calling this method, then the new error is chained on top of the existing one. Otherwise, the function creates a new error without initializing its
__cause__
field.
-
void raise_from(python_error &e, handle type, const char *fmt, ...)¶
Convenience wrapper around
chain_error
. It takes an existing Python error (e.g. caught in acatch
block) and creates an additional Python exception with the current error as cause. It then re-raisespython_error
. The argumentfmt
is aprintf
-style format string interpreted byPyErr_FormatV
.Usage of this function is explained in the documentation section on exception chaining.
-
void raise(const char *fmt, ...)¶
This function takes a
printf
-style format string with arguments and then raises astd::runtime_error
with the formatted string. The function has no dependence on Python, and nanobind merely includes it for convenience.
-
void raise_type_error(const char *fmt, ...)¶
This function is analogous to
raise()
, except that it raises abuiltin_exception
that will convert into a PythonTypeError
when crossing the language interface.
-
void raise_python_error()¶
This function should only be called if a Python error status was set by a prior operation, which should now be raised as a C++ exception. The function is analogous to the statement
throw python_error();
but compiles into more compact code.
Casting¶
-
template<typename T, typename Derived>
T cast(const detail::api<Derived> &value, bool convert = true)¶ Convert the Python object
value
(typically ahandle
or aobject
subclass) into a C++ object of typeT
.When the
convert
argument is set totrue
(the default), the implementation may also attempt implicit conversions to perform the cast.The function raises a
cast_error
when the conversion fails. Seetry_cast()
for an alternative that never raises.
-
template<typename T, typename Derived>
bool try_cast(const detail::api<Derived> &value, T &out, bool convert = true) noexcept¶ Convert the Python object
value
(typically ahandle
or aobject
subclass) into a C++ object of typeT
, and store it in the output parameterout
.When the
convert
argument is set totrue
(the default), the implementation may also attempt implicit conversions to perform the cast.The function returns
false
when the conversion fails. In this case, theout
parameter is left untouched. Seecast()
for an alternative that instead raises an exception in this case.
-
template<typename T>
object cast(T &&value, rv_policy policy = rv_policy::automatic_reference)¶ Convert the C++ object
value
into a Python object. The return value policypolicy
is used to handle ownership-related questions when a new Python object must be created.The function raises a
cast_error
when the conversion fails.
-
template<typename T>
object cast(T &&value, rv_policy policy, handle parent)¶ Convert the C++ object
value
into a Python object. The return value policypolicy
is used to handle ownership-related questions when a new Python object must be created. A validparent
object is required when specifying areference_internal
return value policy.The function raises a
cast_error
when the conversion fails.
-
template<typename T>
object find(const T &value) noexcept¶ Return the Python object associated with the C++ instance
value
. When no such object can be found, the function it returns an invalid object (detail::api::is_valid()
isfalse
).
-
template<rv_policy policy = rv_policy::automatic, typename ...Args>
tuple make_tuple(Args&&... args)¶ Create a Python tuple from a sequence of C++ objects
args...
. The return value policypolicy
is used to handle ownership-related questions when a new Python objects must be created.The function raises a
cast_error
when the conversion fails.
Common binding annotations¶
The following annotations can be specified in both function and class bindings.
-
struct scope¶
-
scope(handle value)¶
Captures the Python scope (e.g., a
module_
ortype_object
) in which the function or class should be registered.
-
scope(handle value)¶
Function binding annotations¶
The following annotations can be specified using the variable-length Extra
parameter of module_::def()
, class_::def()
,
cpp_function()
, etc.
-
struct name¶
-
name(const char *value)¶
Specify this annotation to override the name of the function.
nanobind will internally copy the string when creating a function binding, hence dynamically generated arguments with a limited lifetime are legal.
-
name(const char *value)¶
-
struct arg¶
Function argument annotation to enable keyword-based calling, default arguments, passing
None
, and implicit conversion hints. Note that when a function argument should be annotated, you must specify annotations for all arguments of that function.Example use:
m.def("add", [](int a, int b) { return a + b; }, nb::arg("a"), nb::arg("b"));
It is usually convenient to add the following
using
declaration to your binding code.using namespace nb::literals;
In this case, the argument annotations can be shortened:
m.def("add", [](int a, int b) { return a + b; }, "a"_a, "b"_a);
-
explicit arg(const char *name = nullptr)¶
Create a function argument annotation. The name is optional.
-
template<typename T>
arg_v operator=(T &&value) const¶ Return an argument annotation that is like this one but also assigns a default value to the argument. The default will be converted into a Python object immediately, so its bindings must have already been defined.
-
arg &none(bool value = true)¶
Set a flag noting that the function argument accepts
None
. Can only be used for python wrapper types (e.g.handle
,int_
) and types that have been bound usingclass_
. You cannot use this to implement functions that accept null pointers to builtin C++ types likeint *i = nullptr
.
-
arg &noconvert(bool value = true)¶
Set a flag noting that implicit conversion should never be performed for this function argument.
-
arg &sig(const char *sig)¶
Override the signature of the default argument value. This is useful when the argument value is unusually complex so that the default method to explain it in docstrings and stubs (
str(value)
) does not produce acceptable output.
-
arg_locked lock()¶
Return an argument annotation that is like this one but also requests that this argument be locked when dispatching a function call in free-threaded Python extensions. It does nothing in regular GIL-protected extensions.
-
explicit arg(const char *name = nullptr)¶
-
struct is_method¶
Indicate that the bound function is a method.
-
struct is_operator¶
Indicate that the bound operator represents a special double underscore method (
__add__
,__radd__
, etc.) that implements an arithmetic operation.When a bound functions with this annotation is called with incompatible arguments, it will return
NotImplemented
rather than raising aTypeError
.
-
struct is_implicit¶
Indicate that the bound constructor can be used to perform implicit conversions.
-
struct lock_self¶
Indicate that the implicit
self
argument of a method should be locked when dispatching a call in a free-threaded extension. This annotation does nothing in regular GIL-protected extensions.
-
template<typename ...Ts>
struct call_guard¶ Invoke the call guard(s)
Ts
when the bound function executes. The RAII helpergil_scoped_release
is often combined with this feature.
-
template<size_t Nurse, size_t Patient>
struct keep_alive¶ Following evaluation of the bound function, keep the object referenced by index
Patient
alive as long as the object with indexNurse
exists. This uses the following indexing convention:Index
0
refers to the return value of methods. It should not be used in constructors or functions that do not return a result.Index
1
refers to the first argument. In methods and constructors, index1
refers to the implicitthis
pointer, while regular arguments begin at index2
.
The annotation has the following runtime characteristics:
It does nothing when the nurse or patient object are
None
.It raises an exception when the nurse object is neither weak-referenceable nor an instance of a binding created via
nb::class_<..>
.
Two additional caveats regarding
keep_alive
are noteworthy:It usually doesn’t make sense to specify a
Nurse
orPatient
for an argument or return value handled by a type caster (e.g., a STL vector handled via the include directive#include <nanobind/stl/vector.h>
). That’s because type casters copy-convert the Python object into an equivalent C++ object, whose lifetime is decoupled from the original Python object. However, thekeep_alive
annotation only affects the lifetime of Python objects and not their C++ copy.Dispatching a Python → C++ function call may require the implicit conversion of function arguments. In this case, the objects passed to the C++ function differ from the originally specified arguments. The
Nurse
andPatient
annotation always refer to the final object following implicit conversion.
-
struct sig¶
-
sig(const char *value)¶
This is both a class and a function binding annotation.
When used in functions bindings, it provides complete control over the function’s type signature by replacing the automatically generated version with
value
. You can use it to add or change arguments and return values, tweak how default values are rendered, and add custom decorators.Here is an example:
nb::def("function_name", &function_name, nb::sig( "@decorator(decorator_args..)\n "def function_name(arg_1: type_1 = def_1, ...) -> ret" ));
When used in class bindings, the annotation enables complete control over how the class is rendered by nanobind’s
stubgen
program. You can use it add decorators, specifytyping.TypeVar
-parameterized base classes, metaclasses, etc.Here is an example:
nb::class_<Class>(m, "Class", nb::sig( "@decorator(decorator_args..)\n" "class Class(Base1[T], Base2, meta=Meta)" ));
Deviating significantly from the nanobind-generated signature likely means that the class or function declaration is a lie, but such lies can be useful to type-check complex binding projects.
Specifying decorators isn’t required—the above are just examples to show that this is possible.
nanobind will internally copy the signature during function/type creation, hence dynamically generated strings with a limited lifetime are legal.
The provided string should be valid Python signature, but without a trailing colon (
":"
) or trailing newline. Furthermore, nanobind analyzes the string and expects to find the name of the function or class on the last line between the"def"
/"class"
prefix and the opening parenthesis.For function bindings, this name must match the specified function name in
.def("name", ..)
-style binding declarations, and for class bindings, the specified name must match thename
argument ofnb::class_
.
-
sig(const char *value)¶
-
enum class rv_policy¶
A return value policy determines the question of ownership when a bound function returns a previously unknown C++ instance that must now be converted into a Python object.
Return value policies apply to functions that return values handled using class bindings, which means that their Python equivalent was registered using
class_<...>
. They are ignored in most other cases. One exception are STL types handled using type casters (e.g.std::vector<T>
), which contain a nested typeT
handled using class bindings. In this case, the return value policy also applies recursively.A return value policy is unnecessary when the type itself clarifies ownership (e.g.,
std::unique_ptr<T>
,std::shared_ptr<T>
, a type with intrusive reference counting).The following policies are available (where
automatic
is the default). Please refer to the return value policy section of the main documentation, which clarifies the list below using concrete examples.-
enumerator take_ownership¶
Create a Python object that wraps the existing C++ instance and takes full ownership of it. No copies are made. Python will call the C++ destructor and
delete
operator when the Python wrapper is garbage collected at some later point. The C++ side must relinquish ownership and is not allowed to destruct the instance, or undefined behavior will ensue.
-
enumerator copy¶
Copy-construct a new Python object from the C++ instance. The new copy will be owned by Python, while C++ retains ownership of the original.
-
enumerator move¶
Move-construct a new Python object from the C++ instance. The new object will be owned by Python, while C++ retains ownership of the original (whose contents were likely invalidated by the move operation).
-
enumerator reference¶
Create a Python object that wraps the existing C++ instance without taking ownership of it. No copies are made. Python will never call the destructor or
delete
operator, even when the Python wrapper is garbage collected.
-
enumerator reference_internal¶
A safe extension of the
reference
policy for methods that implement some form of attribute access. It creates a Python object that wraps the existing C++ instance without taking ownership of it. Additionally, it adjusts reference counts to keeps the method’s implicitself
argument alive until the newly created object has been garbage collected.
-
enumerator none¶
This is the most conservative policy: it simply refuses the cast unless the C++ instance already has a corresponding Python object, in which case the question of ownership becomes moot.
-
enumerator automatic¶
This is the default return value policy, which falls back to
take_ownership
when the return value is a pointer,move
when it is a rvalue reference, andcopy
when it is a lvalue reference.
-
enumerator take_ownership¶
-
struct kw_only¶
Indicate that all following function parameters are keyword-only. This may only be used if you supply an
arg
annotation for each parameters, because keyword-only parameters are useless if they don’t have names. For example, if you writeint some_func(int one, const char* two); m.def("some_func", &some_func, nb::arg("one"), nb::kw_only(), nb::arg("two"));
then in Python you can write
some_func(42, two="hi")
, orsome_func(one=42, two="hi")
, but notsome_func(42, "hi")
.Just like in Python, any parameters appearing after variadic
*args
are implicitly keyword-only. You don’t need to include thekw_only
annotation in this case, but if you do include it, it must be in the correct position: immediately after thearg
annotation for the variadic*args
parameter.
-
template<typename T>
struct for_getter¶ When defining a property with a getter and a setter, you can use this to only pass a function binding attribute to the getter part. An example is shown below.
nb::class_<MyClass>(m, "MyClass") .def_prop_rw("value", &MyClass::value, nb::for_getter(nb::sig("def value(self, /) -> int")), nb::for_setter(nb::sig("def value(self, value: int, /) -> None")), nb::for_getter("docstring for getter"), nb::for_setter("docstring for setter"));
-
template<typename T>
struct for_setter¶ Analogous to
for_getter
, but for setters.
-
template<typename Policy>
struct call_policy¶ Request that custom logic be inserted around each call to the bound function, by calling
Policy::precall(args, nargs, cleanup)
before Python-to-C++ argument conversion, andPolicy::postcall(args, nargs, ret)
after C++-to-Python return value conversion.If multiple call policy annotations are provided for the same function, then their precall and postcall hooks will both execute left-to-right according to the order in which the annotations were specified when binding the function.
The
nb::call_guard<T>()
annotation should be preferred overcall_policy
unless the wrapper logic depends on the function arguments or return value. If both annotations are combined, thennb::call_guard<T>()
always executes on the “inside” (closest to the bound function, after argument conversions and before return value conversion) regardless of its position in the function annotations list.Your
Policy
class must define two static member functions:-
static void precall(PyObject **args, size_t nargs, detail::cleanup_list *cleanup);¶
A hook that will be invoked before calling the bound function. More precisely, it is called after any argument locks have been obtained, but before the Python arguments are converted to C++ objects for the function call.
This hook may access or modify the function arguments using the args array, which holds borrowed references in one-to-one correspondence with the C++ arguments of the bound function. If the bound function is a method, then
args[0]
is its self argument. nargs is the number of function arguments. It is actually passed asstd::integral_constant<size_t, N>()
, so you can match on that type if you want to do compile-time checks with it.The cleanup list may be used as it is used in type casters, to cause some Python object references to be released at some point after the bound function completes. (If the bound function is part of an overload set, the cleanup list isn’t released until all overloads have been tried.)
precall()
may choose to throw a C++ exception. If it does, it will preempt execution of the bound function, and the exception will be treated as if the bound function had thrown it.
-
static void postcall(PyObject **args, size_t nargs, handle ret);¶
A hook that will be invoked after calling the bound function and converting its return value to a Python object, but only if the bound function returned normally.
args stores the Python object arguments, with the same semantics as in
precall()
, except that arguments that participated in implicit conversions will have had theirargs[i]
pointer updated to reflect the new Python object that the implicit conversion produced. nargs is the number of arguments, passed as astd::integral_constant
in the same way as forprecall()
.ret is the bound function’s return value. If the bound function returned normally but its C++ return value could not be converted to a Python object, then
postcall()
will execute with ret set to null, and the Python error indicator might or might not be set to explain why.If the bound function did not return normally – either because its Python object arguments couldn’t be converted to the appropriate C++ types, or because the C++ function threw an exception – then
postcall()
will not execute. If you need some cleanup logic to run even in such cases, yourprecall()
can add a capsule object to the cleanup list; its destructor will run eventually, but with no promises as to when. Anb::call_guard
might be a better choice.postcall()
may choose to throw a C++ exception. If it does, the result of the wrapped function will be destroyed, and the exception will be raised in its place, as if the bound function had thrown it just before returning.
Here is an example policy to demonstrate.
nb::call_policy<returns_references_to<I>>()
behaves likenb::keep_alive<0, I>()
, except that the return value is a treated as a list of objects rather than a single one.template <size_t I> struct returns_references_to { static void precall(PyObject **, size_t, nb::detail::cleanup_list *) {} template <size_t N> static void postcall(PyObject **args, std::integral_constant<size_t, N>, nb::handle ret) { static_assert(I > 0 && I < N, "I in returns_references_to<I> must be in the " "range [1, number of C++ function arguments]"); if (!nb::isinstance<nb::sequence>(ret)) { throw std::runtime_error("return value should be a sequence"); } for (nb::handle nurse : ret) { nb::detail::keep_alive(nurse.ptr(), args[I]); } } };
For a more complex example (binding an object that uses trivially-copyable callbacks), see
tests/test_callbacks.cpp
in the nanobind source distribution.-
static void precall(PyObject **args, size_t nargs, detail::cleanup_list *cleanup);¶
Class binding annotations¶
The following annotations can be specified using the variable-length Extra
parameter of the constructor class_::class_()
.
Besides the below options, also refer to the sig
which is
usable in both function and class bindings. It can be used to override class
declarations in generated stubs,
-
struct is_final¶
Indicate that a type cannot be subclassed.
-
struct dynamic_attr¶
Indicate that instances of a type require a Python dictionary to support the dynamic addition of attributes.
-
struct is_weak_referenceable¶
Indicate that instances of a type require a weak reference list so that they can be referenced by the Python
weakref.*
types.
-
struct is_generic¶
If present, nanobind will add a
__class_getitem__
function to the newly created type that permits constructing parameterized versions (e.g.,MyType[int]
). The implementation of this function is equivalent todef __class_getitem__(cls, value): import types return types.GenericAlias(cls, value)
See the section on creating generic types for an example.
This feature is only supported on Python 3.9+. Nanobind will ignore the attribute in Python 3.8 builds.
-
template<typename T>
struct supplement¶ Indicate that
sizeof(T)
bytes of memory should be set aside to store supplemental data in the type object. See Supplemental type data for more information.
-
struct type_slots¶
-
type_slots(PyType_Slot *value)¶
nanobind uses the
PyType_FromSpec
Python C API interface to construct types. In certain advanced use cases, it may be helpful to append additional type slots during type construction. This class binding annotation can be used to accomplish this. The provided list should be followed by a zero-initializedPyType_Slot
element. See Customizing type creation for more information about this feature.-
type_slots(PyType_Slot *value)¶
-
template<typename T>
struct intrusive_ptr¶ nanobind provides a custom interface for intrusive reference-counted C++ types that nicely integrate with Python reference counting. See the separate section on this topic. This annotation marks a type as compatible with this interface.
Enum binding annotations¶
The following annotations can be specified using the variable-length
Extra
parameter of the constructor enum_::enum_()
.
-
struct is_arithmetic¶
Indicate that the enumeration supports arithmetic operations. This enables both unary (
-
,~
,abs()
) and binary (+
,-
,*
,//
,&
,|
,^
,<<
,>>
) operations with operands of either enumeration or numeric types.The result will be as if the operands were first converted to integers. (So
Shape(2) + Shape(1) == 3
andShape(2) * 1.5 == 3.0
.) It is unspecified whether operations on mixed enum types (such asShape.Circle + Color.Red
) are permissible.Passing this annotation changes the Python enumeration parent class to either
enum.IntEnum
orenum.IntFlag
, depending on whether or not the flag enumeration attribute is also specified (seeis_flag
).
-
struct is_flag¶
Indicate that the enumeration supports bit-wise operations. This enables the operators (
|
,&
,^
, and~
) with two enumerators as operands.The result has the same type as the operands, i.e.,
Shape(2) | Shape(1)
will be equivalent toShape(3)
.Passing this annotation changes the Python enumeration parent class to either
enum.IntFlag
orenum.Flag
, depending on whether or not the enumeration is also marked to support arithmetic operations (seeis_arithmetic
).
Function binding¶
-
object cpp_function(Func &&f, const Extra&... extra)¶
Convert the function
f
into a Python callable. This function has a few overloads (not shown here) to separately deal with function/method pointers and lambda functions.The variable length
extra
parameter can be used to pass a docstring and other function binding annotations.
Class binding¶
-
template<typename T, typename ...Ts>
class class_ : public object¶ Binding helper class to expose a custom C++ type
T
(declared using either theclass
orstruct
keyword) in Python.The variable length parameter
Ts
is optional and can be used to specify the base class ofT
and/or an alias needed to realize trampoline classes.When the type
T
was previously already registered (either within the same extension or another extension), theclass_<..>
declaration is redundant. nanobind will print a warning message in this case:RuntimeWarning: nanobind: type 'MyType' was already registered!
The
class_<..>
instance will subsequently wrap the original type object instead of creating a new one.-
template<typename ...Extra>
class_(handle scope, const char *name, const Extra&... extra)¶ Bind the type
T
to the identifiername
within the scopescope
. The variable lengthextra
parameter can be used to pass a docstring and other class binding annotations.
-
template<typename Func, typename ...Extra>
class_ &def(const char *name, Func &&f, const Extra&... extra)¶ Bind the function
f
and assign it to the class membername
. The variable lengthextra
parameter can be used to pass a docstring and other function binding annotations.This function has two overloads (listed just below) to handle constructor binding declarations.
Example:
struct A { void f() { /*...*/ } }; nb::class_<A>(m, "A") .def(nb::init<>()) // Bind the default constructor .def("f", &A::f); // Bind the method A::f
-
template<typename ...Args, typename ...Extra>
class_ &def(init<Args...> arg, const Extra&... extra)¶ Bind a constructor. The variable length
extra
parameter can be used to pass a docstring and other function binding annotations.
-
template<typename Arg, typename ...Extra>
class_ &def(init_implicit<Arg> arg, const Extra&... extra)¶ Bind a constructor that may be used for implicit type conversions. The constructor must take a single argument of an unspecified type
Arg
.When nanobind later tries to dispatch a function call requiring an argument of type
T
whileArg
was actually provided, it will run this constructor to perform the necessary conversion.The variable length
extra
parameter can be used to pass a docstring and other function binding annotations.This constructor generates more compact code than a separate call to
implicitly_convertible()
, but is otherwise equivalent.
-
template<typename Func, typename ...Extra>
class_ &def(new_<Func> arg, const Extra&... extra)¶ Bind a C++ factory function as a Python object constructor (
__new__
). This is an advanced feature; prefernb::init<..>
where possible. See the discussion of customizing object creation for more details.
-
template<typename C, typename D, typename ...Extra>
class_ &def_rw(const char *name, D C::* p, const Extra&... extra)¶ Bind the field
p
and assign it to the class membername
. nanobind constructs aproperty
object with read-write access (hence therw
suffix) to do so.Every access from Python will read from or write to the C++ field while performing a suitable conversion (using type casters, bindings, or wrappers) as determined by its type.
The variable length
extra
parameter can be used to pass a docstring and other function binding annotations that are forwarded to the anonymous functions used to construct the property. Use thenb::for_getter
andnb::for_setter
to pass annotations specifically to the setter or getter part.Example:
struct A { int value; }; nb::class_<A>(m, "A") .def_rw("value", &A::value); // Enable mutable access to the field A::value
-
template<typename C, typename D, typename ...Extra>
class_ &def_ro(const char *name, D C::* p, const Extra&... extra)¶ Bind the field
p
and assign it to the class membername
. nanobind constructs aproperty
object with read only access (hence thero
suffix) to do so.Every access from Python will read the C++ field while performing a suitable conversion (using type casters, bindings, or wrappers) as determined by its type.
The variable length
extra
parameter can be used to pass a docstring and other function binding annotations that are forwarded to the anonymous functions used to construct the property.Example:
struct A { int value; }; nb::class_<A>(m, "A") .def_ro("value", &A::value); // Enable read-only access to the field A::value
-
template<typename Getter, typename Setter, typename ...Extra>
class_ &def_prop_rw(const char *name, Getter &&getter, Setter &&setter, const Extra&... extra)¶ Construct a mutable (hence the
rw
suffix) Pythonproperty
and assign it to the class membername
. Every read access will call the functiongetter
with theT
instance, and every write access will call thesetter
with theT
instance and value to be assigned.The variable length
extra
parameter can be used to pass a docstring and other function binding annotations. Use thenb::for_getter
andnb::for_setter
to pass annotations specifically to the setter or getter part.Note that this function implicitly assigns the
rv_policy::reference_internal
return value policy togetter
(as opposed to the usualrv_policy::automatic
). Provide an explicit return value policy as part of theextra
argument to override this.Example: the example below uses
def_prop_rw()
to expose a C++ setter/getter pair as a more “Pythonic” property:class A { public: A(int value) : m_value(value) { } void set_value(int value) { m_value = value; } int value() const { return m_value; } private: int m_value; }; nb::class_<A>(m, "A") .def(nb::init<int>()) .def_prop_rw("value", [](A &t) { return t.value() ; }, [](A &t, int value) { t.set_value(value); });
-
template<typename Getter, typename ...Extra>
class_ &def_prop_ro(const char *name, Getter &&getter, const Extra&... extra)¶ Construct a read-only (hence the
ro
suffix) Pythonproperty
and assign it to the class membername
. Every read access will call the functiongetter
with theT
instance.The variable length
extra
parameter can be used to pass a docstring and other function binding annotations.Note that this function implicitly assigns the
rv_policy::reference_internal
return value policy togetter
(as opposed to the usualrv_policy::automatic
). Provide an explicit return value policy as part of theextra
argument to override this.Example: the example below uses
def_prop_ro()
to expose a C++ getter as a more “Pythonic” property:class A { public: A(int value) : m_value(value) { } int value() const { return m_value; } private: int m_value; }; nb::class_<A>(m, "A") .def(nb::init<int>()) .def_prop_ro("value", [](A &t) { return t.value() ; });
-
template<typename Func, typename ...Extra>
class_ &def_static(const char *name, Func &&f, const Extra&... extra)¶ Bind the static function
f
and assign it to the class membername
. The variable lengthextra
parameter can be used to pass a docstring and other function binding annotations.Example:
struct A { static void f() { /*...*/ } }; nb::class_<A>(m, "A") .def_static("f", &A::f); // Bind the static method A::f
-
template<typename D, typename ...Extra>
class_ &def_rw_static(const char *name, D *p, const Extra&... extra)¶ Bind the static field
p
and assign it to the class membername
. nanobind constructs a classproperty
object with read-write access (hence therw
suffix) to do so.Every access from Python will read from or write to the static C++ field while performing a suitable conversion (using type casters, bindings, or wrappers) as determined by its type.
The variable length
extra
parameter can be used to pass a docstring and other function binding annotations that are forwarded to the anonymous functions used to construct the property Use thenb::for_getter
andnb::for_setter
to pass annotations specifically to the setter or getter part.Example:
struct A { inline static int value = 5; }; nb::class_<A>(m, "A") // Enable mutable access to the static field A::value .def_rw_static("value", &A::value);
-
template<typename D, typename ...Extra>
class_ &def_ro_static(const char *name, D *p, const Extra&... extra)¶ Bind the static field
p
and assign it to the class membername
. nanobind constructs a classproperty
object with read-only access (hence thero
suffix) to do so.Every access from Python will read the static C++ field while performing a suitable conversion (using type casters, bindings, or wrappers) as determined by its type.
The variable length
extra
parameter can be used to pass a docstring and other function binding annotations that are forwarded to the anonymous functions used to construct the propertyExample:
struct A { inline static int value = 5; }; nb::class_<A>(m, "A") // Enable read-only access to the static field A::value .def_ro_static("value", &A::value);
-
template<typename Getter, typename Setter, typename ...Extra>
class_ &def_prop_rw_static(const char *name, Getter &&getter, Setter &&setter, const Extra&... extra)¶ Construct a mutable (hence the
rw
suffix) Pythonproperty
and assign it to the class membername
. Every read access will call the functiongetter
withT
’s Python type object, and every write access will call thesetter
withT
’s Python type object and value to be assigned.The variable length
extra
parameter can be used to pass a docstring and other function binding annotations. Use thenb::for_getter
andnb::for_setter
to pass annotations specifically to the setter or getter part.Note that this function implicitly assigns the
rv_policy::reference
return value policy togetter
(as opposed to the usualrv_policy::automatic
). Provide an explicit return value policy as part of theextra
argument to override this.Example: the example below uses
def_prop_rw_static()
to expose a static C++ setter/getter pair as a more “Pythonic” property:class A { public: static void set_value(int value) { s_value = value; } static int value() { return s_value; } private: inline static int s_value = 5; }; nb::class_<A>(m, "A") .def_prop_rw_static("value", [](nb::handle /*unused*/) { return A::value() ; }, [](nb::handle /*unused*/, int value) { A::set_value(value); });
-
template<typename Getter, typename ...Extra>
class_ &def_prop_ro_static(const char *name, Getter &&getter, const Extra&... extra)¶ Construct a read-only (hence the
ro
suffix) Pythonproperty
and assign it to the class membername
. Every read access will call the functiongetter
withT
’s Python type object.The variable length
extra
parameter can be used to pass a docstring and other function binding annotations.Note that this function implicitly assigns the
rv_policy::reference
return value policy togetter
(as opposed to the usualrv_policy::automatic
). Provide an explicit return value policy as part of theextra
argument to override this.Example: the example below uses
def_prop_ro_static()
to expose a static C++ getter as a more “Pythonic” property:class A { public: static int value() { return s_value; } private: inline static int s_value = 5; }; nb::class_<A>(m, "A") .def_prop_ro_static("value", [](nb::handle /*unused*/) { return A::value() ; });
-
template<detail::op_id id, detail::op_type ot, typename L, typename R, typename ...Extra>
class_ &def(const detail::op_<id, ot, L, R> &op, const Extra&... extra)¶ This interface provides convenient syntax sugar to replace relatively lengthy method bindings with shorter operator bindings. To use it, you will need an extra include directive:
#include <nanobind/operators.h>
Below is an example type with three arithmetic operators in C++ (unary negation and 2 binary subtraction overloads) along with corresponding bindings.
Example:
struct A { float value; A operator-() const { return { -value }; } A operator-(const A &o) const { return { value - o.value }; } A operator-(float o) const { return { value - o }; } }; nb::class_<A>(m, "A") .def(nb::init<float>()) .def(-nb::self) .def(nb::self - nb::self) .def(nb::self - float());
Bind an arithmetic or comparison operator expressed in short-hand form (e.g.,
.def(nb::self + nb::self)
).
-
template<typename ...Extra>
-
template<typename T>
class enum_ : public class_<T>¶ Class binding helper for scoped and unscoped C++ enumerations.
-
template<typename ...Extra>
NB_INLINE enum_(handle scope, const char *name, const Extra&... extra)¶ Bind the enumeration of type
T
to the identifiername
within the scopescope
. The variable lengthextra
parameter can be used to pass a docstring and other enum binding annotations (currently, onlyis_arithmetic
is supported).
-
template<typename ...Extra>
-
template<typename T>
class exception : public object¶ Class binding helper for declaring new Python exception types
-
exception(handle scope, const char *name, handle base = PyExc_Exception)¶
Create a new exception type identified by
name
that derives frombase
, and install it inscope
. The constructor also callsregister_exception_translator()
to register a new exception translator that converts caught C++ exceptions of typeT
into the newly created Python equivalent.
-
exception(handle scope, const char *name, handle base = PyExc_Exception)¶
-
template<typename ...Args>
struct init¶ nanobind uses this simple helper class to capture the signature of a constructor. It is only meant to be used in binding declarations done via
class_::def()
.Sometimes, it is necessary to bind constructors that don’t exist in the underlying C++ type (meaning that they are specific to the Python bindings). Because
init
only works for existing C++ constructors, this requires a manual workaround noting thatnb::class_<MyType>(m, "MyType") .def(nb::init<const char*, int>());
is syntax sugar for the following lower-level implementation using “placement new”:
nb::class_<MyType>(m, "MyType") .def("__init__", [](MyType* t, const char* arg0, int arg1) { new (t) MyType(arg0, arg1); });
The provided lambda function will be called with a pointer to uninitialized memory that has already been allocated (this memory region is co-located with the Python object for reasons of efficiency). The lambda function can then either run an in-place constructor and return normally (in which case the instance is assumed to be correctly constructed) or fail by raising an exception.
-
template<typename Arg>
struct init_implicit¶ See
init
for detail on binding constructors. The main difference betweeninit
andinit_implicit
is that the latter only supports constructors taking a single argumentArg
, and that it marks the constructor as usable for implicit conversions fromArg
.Sometimes, it is necessary to bind implicit conversion-capable constructors that don’t exist in the underlying C++ type (meaning that they are specific to the Python bindings). This can be done manually noting that
nb::class_<MyType>(m, "MyType") .def(nb::init_implicit<const char*>());
can be replaced by the lower-level code
nb::class_<MyType>(m, "MyType") .def("__init__", [](MyType* t, const char* arg0) { new (t) MyType(arg0); }); nb::implicitly_convertible<const char*, MyType>();
-
template<typename Func>
struct new_¶ This is a small helper class that indicates to
class_::def()
that a particular lambda or static method provides a Python object constructor (__new__
) for the class being bound. Normally, you would useinit
instead if possible, in order to cooperate with nanobind’s usual object creation process. Usingnew_
replaces that process entirely. This is principally useful when some C++ type of interest can only provide pointers to its instances, rather than allowing them to be constructed directly.Like
init
, the only use of anew_
object is as an argument toclass_::def()
.Example use:
class MyType { private: MyType(); public: static std::shared_ptr<MyType> create(); int value = 0; }; nb::class_<MyType>(m, "MyType") .def(nb::new_(&MyType::create));
Given this example code, writing
MyType()
in Python would produce a Python object wrapping the result ofMyType::create()
in C++. If multiple calls tocreate()
return pointers to the same C++ object, these will turn into references to the same Python object as well.See the discussion of customizing Python object creation for more information.
GIL Management¶
These two RAII helper
classes acquire and release the Global Interpreter Lock (GIL) in a given
scope. The gil_scoped_release
helper is often combined with the
call_guard
, as in
m.def("expensive", &expensive, nb::call_guard<nb::gil_scoped_release>());
This releases the interpreter lock while expensive
is running, which permits
running it in parallel from multiple Python threads.
-
struct gil_scoped_acquire¶
-
gil_scoped_acquire()¶
Acquire the GIL
-
~gil_scoped_acquire()¶
Release the GIL
-
gil_scoped_acquire()¶
-
struct gil_scoped_release¶
-
gil_scoped_release()¶
Release the GIL (must be currently held)
In free-threaded extensions, this operation also temporarily releases all argument locks held by the current thread.
-
~gil_scoped_release()¶
Reacquire the GIL
-
gil_scoped_release()¶
Free-threading¶
Nanobind provides abstractions to implement additional locking that is needed to ensure the correctness of free-threaded Python extensions.
-
struct ft_mutex¶
Object-oriented wrapper representing a PyMutex. It can be slightly more efficient than OS/language-provided primitives (e.g.,
std::thread
,pthread_mutex_t
) and should generally be preferred when adding critical sections to Python bindings.In Python builds without free-threading, this class does nothing. It has no attributes and the
lock()
andunlock()
functions return immediately.-
ft_mutex()¶
Create a new (unlocked) mutex.
-
void lock()¶
Acquire the mutex.
-
void unlock()¶
Release the mutex.
-
ft_mutex()¶
-
struct ft_lock_guard¶
This class provides a RAII lock guard analogous to
std::lock_guard
andstd::unique_lock
.-
ft_lock_guard(ft_mutex &mutex)¶
Call
mutex.lock()
(no-op in non-free-threaded builds).
-
~ft_lock_guard()¶
Call
mutex.unlock()
(no-op in non-free-threaded builds).
-
ft_lock_guard(ft_mutex &mutex)¶
-
struct ft_object_guard¶
This class provides a RAII guard that locks a single Python object within a local scope (in contrast to
ft_lock_guard
, which locks a mutex).It is a thin wrapper around the Python critical section API. Please refer to the Python documentation for details on the semantics of this relaxed form of critical section (in particular, Python critical sections may release previously held locks).
In Python builds without free-threading, this class does nothing—the constructor and destructor return immediately.
-
~ft_object_guard()¶
Unlock the object
h
(no-op in non-free-threaded builds)
-
~ft_object_guard()¶
-
struct ft_object2_guard¶
This class provides a RAII guard that locks two Python object within a local scope (in contrast to
ft_lock_guard
, which locks a mutex).It is a thin wrapper around the Python critical section API. Please refer to the Python documentation for details on the semantics of this relaxed form of critical section (in particular, Python critical sections may release previously held locks).
In Python builds without free-threading, this class does nothing—the constructor and destructor return immediately.
-
ft_object2_guard(handle h1, handle h2)¶
Lock the objects
h1
andh2
(no-op in non-free-threaded builds)
-
~ft_object2_guard()¶
Unlock the objects
h1
andh2
(no-op in non-free-threaded builds)
-
ft_object2_guard(handle h1, handle h2)¶
Low-level type and instance access¶
nanobind exposes a low-level interface to provide fine-grained control over the sequence of steps that instantiates a Python object wrapping a C++ instance. A thorough explanation of these features is provided in a separate section.
Type objects¶
-
size_t type_size(handle h)¶
Assuming that
h
represents a bound type (seetype_check()
), return its size in bytes.
-
size_t type_align(handle h)¶
Assuming that
h
represents a bound type (seetype_check()
), return its alignment in bytes.
-
const std::type_info &type_info(handle h)¶
Assuming that
h
represents a bound type (seetype_check()
), return its C++ RTTI record.
-
template<typename T>
T &type_supplement(handle h)¶ Return a reference to supplemental data stashed in a type object. The type
T
must exactly match the type specified in thenb::supplement<T>
annotation used when creating the type; no type check is performed, and invalid supplement accesses may crash the interpreter. Also refer tonb::supplement<T>
.
-
str type_name(handle h)¶
Return the full (module-qualified) name of a type object as a Python string.
-
void *type_get_slot(handle h, int slot_id)¶
On Python 3.10+, this function is a simple wrapper around the Python C API function
PyType_GetSlot
that provides stable API-compatible access to type object members. On Python 3.9 and earlier, the official function did not work on non-heap types. The nanobind version consistently works on heap and non-heap types across Python versions.
Instances¶
The documentation below refers to two per-instance flags with the following meaning:
ready: is the instance fully constructed? nanobind will not permit passing the instance to a bound C++ function when this flag is unset.
destruct: should nanobind call the C++ destructor when the instance is garbage-collected?
-
bool inst_check(handle h)¶
Returns
true
ifh
represents an instance of a type that was previously bound viaclass_
.
-
template<typename T>
T *inst_ptr(handle h)¶ Assuming that
h
represents an instance of a type that was previously bound viaclass_
, return a pointer to the underlying C++ instance.The function does not check that
h
actually contains an instance with C++ typeT
.
-
object inst_alloc(handle h)¶
Assuming that
h
represents a type object that was previously created viaclass_
(seetype_check()
), allocate an unitialized object of typeh
and return it. The ready and destruct flags of the returned instance are both set tofalse
.
-
object inst_alloc_zero(handle h)¶
Assuming that
h
represents a type object that was previously created viaclass_
(seetype_check()
), allocate a zero-initialized object of typeh
and return it. The ready and destruct flags of the returned instance are both set totrue
.This operation is equivalent to calling
inst_alloc()
followed byinst_zero()
.
-
object inst_reference(handle h, void *p, handle parent = handle())¶
Assuming that
h
represents a type object that was previously created viaclass_
(seetype_check()
) create an object of typeh
that wraps an existing C++ instancep
.The ready and destruct flags of the returned instance are respectively set to
true
andfalse
.This is analogous to casting a C++ object with return value policy
rv_policy::reference
.If a
parent
object is specified, the instance keeps this parent alive while the newly created object exists. This is analogous to casting a C++ object with return value policyrv_policy::reference_internal
.
-
object inst_take_ownership(handle h, void *p)¶
Assuming that
h
represents a type object that was previously created viaclass_
(seetype_check()
) create an object of typeh
that wraps an existing C++ instancep
.The ready and destruct flags of the returned instance are both set to
true
.This is analogous to casting a C++ object with return value policy
rv_policy::take_ownership
.
-
void inst_zero(handle h)¶
Zero-initialize the contents of
h
. Sets the ready and destruct flags totrue
.
-
std::pair<bool, bool> inst_state(handle h)¶
Separately query the ready and destruct flags of the instance
h
.
-
void inst_mark_ready(handle h)¶
Simultaneously set the ready and destruct flags of the instance
h
totrue
.
-
void inst_set_state(handle h, bool ready, bool destruct)¶
Separately set the ready and destruct flags of the instance
h
.
-
void inst_destruct(handle h)¶
Destruct the instance
h
. This entails calling the C++ destructor if the destruct flag is set and then setting the ready and destruct fields tofalse
.
-
void inst_copy(handle dst, handle src)¶
Copy-construct the contents of
src
intodst
and set the ready and destruct flags ofdst
totrue
.dst
should be an uninitialized instance of the same type. Note that setting the destruct flag may be problematic ifdst
is an offset into an existing object created usinginst_reference()
(the destructor will be called multiple times in this case). If so, you must useinst_set_state()
to disable the flag following the call toinst_copy()
.New in nanobind v2.0.0: The function is a no-op when
src
anddst
refer to the same object.
-
void inst_move(handle dst, handle src)¶
Analogous to
inst_copy()
, except that the move constructor is used instead of the copy constructor.
-
void inst_replace_copy(handle dst, handle src)¶
Destruct the contents of
dst
(even if the destruct flag isfalse
). Next, copy-construct the contents ofsrc
intodst
and set the ready flag ofdst
. The value of the destruct flag is subsequently set to its value prior to the call.This operation is useful to replace the contents of one instance with that of another regardless of whether
dst
has been created usinginst_alloc()
,inst_reference()
, orinst_take_ownership()
.New in nanobind v2.0.0: The function is a no-op when
src
anddst
refer to the same object.
-
void inst_replace_move(handle dst, handle src)¶
Analogous to
inst_replace_copy()
, except that the move constructor is used instead of the copy constructor.
Global flags¶
-
bool leak_warnings() noexcept¶
Returns whether nanobind warns if any nanobind instances, types, or functions are still alive when the Python interpreter shuts down.
-
bool implicit_cast_warnings() noexcept¶
Returns whether nanobind warns if an implicit conversion was not successful.
-
void set_leak_warnings(bool value) noexcept¶
By default, nanobind loudly complains when any nanobind instances, types, or functions are still alive when the Python interpreter shuts down. Call this function to disable or re-enable leak warnings.
-
void set_implicit_cast_warnings(bool value) noexcept¶
By default, nanobind loudly complains when it attempts to perform an implicit conversion, and when that conversion is not successful. Call this function to disable or re-enable the warnings.
-
inline bool is_alive() noexcept¶
The function returns
true
when nanobind is initialized and ready for use. It returnsfalse
when the Python interpreter has shut down, causing the destruction various nanobind-internal data structures. Having access to this liveness status can be useful to avoid operations that are illegal in the latter context.
Miscellaneous¶
-
str repr(handle h)¶
Return a stringified version of the provided Python object. Equivalent to
repr(h)
in Python.
-
void print(handle value, handle end = handle(), handle file = handle())¶
Invoke the Python
print()
function to print the objectvalue
. If desired, a line endingend
and file handlefile
can be specified.
-
void print(const char *str, handle end = handle(), handle file = handle())¶
Invoke the Python
print()
function to print the null-terminated C-style stringstr
that is encoded using UTF-8 encoding. If desired, a line endingend
and file handlefile
can be specified.
-
Py_hash_t hash(handle h)¶
Hash the given argument like
hash()
in pure Python. The type of the return value (Py_hash_t
) is an implementation-specific signed integer type.
-
template<typename Source, typename Target>
void implicitly_convertible()¶ Indicate that the type
Source
is implicitly convertible intoTarget
(which must refer to a type that was previously bound viaclass_
).Note: the
init_implicit
interface generates more compact code and should be preferred, i.e., usenb::class_<Target>(m, "Target") .def(nb::init_implicit<Source>());
instead of
nb::class_<Target>(m, "Target") .def(nb::init<Source>()); nb::implicitly_convertible<Source, Target>();
The function is provided for reasons of compatibility with pybind11, and as an escape hatch to enable use cases where
init_implicit
is not available (e.g., for custom binding-specific constructors that don’t exist inTarget
type).
-
template<typename T, typename ...Ts>
class typed¶ This helper class provides an interface to parameterize generic types to improve generated Python function signatures (e.g., to turn
list
intolist[MyType]
).Consider the following binding that iterates over a Python list.
m.def("f", [](nb::list l) { for (handle h : l) { // ... } });
Suppose that
f
expects a list ofMyType
objects, which is not clear from the signature. To make this explicit, use thenb::typed<T, Ts...>
wrapper to pass additional type parameters. This has no effect besides clarifying the signature—in particular, nanobind does not insert additional runtime checks!m.def("f", [](nb::typed<nb::list, MyType> l) { for (nb::handle h : l) { // ... } });