pybind11 module

向量数据库大模型云通信

picture.image

头文件

  
#include "pybind11/pybind11.h"  
#include "pybind11/stl.h"  
  
namespace py = pybind11;  

PYBIND11_MODULE

  
PYBIND11_MODULE(_k2, m) {  
  m.doc() = "pybind11 binding of k2";  
  PybindVersion(m);  
  PybindTorch(m);  
}  

  
#define PYBIND11\_CONCAT(first, second) first##second  
  
  
#if defined(PYBIND11\_CPP17)  
#    define PYBIND11\_MAYBE\_UNUSED [[maybe\_unused]]  
#elif defined(\_MSC\_VER) && !defined(\_\_clang\_\_)  
#    define PYBIND11\_MAYBE\_UNUSED  
#else  
#    define PYBIND11\_MAYBE\_UNUSED \_\_attribute\_\_((\_\_unused\_\_))  
#endif  
  
#if !defined(PYBIND11\_EXPORT)  
#    if defined(WIN32) || defined(\_WIN32)  
#        define PYBIND11\_EXPORT \_\_declspec(dllexport)  
#    else  
#        define PYBIND11\_EXPORT \_\_attribute\_\_((visibility("default")))  
#    endif  
#endif  
  
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.  
// See comment for PYBIND11\_MODULE below for why this is marked "maybe unused".  
#define PYBIND11\_PLUGIN\_IMPL(name)                                                                \  
    extern "C" PYBIND11\_MAYBE\_UNUSED PYBIND11\_EXPORT PyObject *PyInit\_##name();                   \  
    extern "C" PYBIND11\_EXPORT PyObject *PyInit\_##name()  

  
// pybind11/detail/common.h  
/** \rst  
    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. The second macro argument defines a variable of type  
    `py::module\_` which can be used to initialize the module.  
  
    The entry point is marked as "maybe unused" to aid dead-code detection analysis:  
    since the entry point is typically only looked up at runtime and not referenced  
    during translation, it would otherwise appear as unused ("dead") code.  
  
    .. code-block:: cpp  
  
        PYBIND11\_MODULE(example, m) {  
            m.doc() = "pybind11 example module";  
  
            // Add bindings here  
            m.def("foo", []() {  
                return "Hello, World!";  
            });  
        }  
\endrst */  
#define PYBIND11\_MODULE(name, variable)                                                           \  
    static ::pybind11::module\_::module\_def PYBIND11\_CONCAT(pybind11\_module\_def\_, name)            \  
        PYBIND11\_MAYBE\_UNUSED;                                                                    \  
    PYBIND11\_MAYBE\_UNUSED                                                                         \  
    static void PYBIND11\_CONCAT(pybind11\_init\_, name)(::pybind11::module\_ &);                     \  
    PYBIND11\_PLUGIN\_IMPL(name) {                                                                  \  
        PYBIND11\_CHECK\_PYTHON\_VERSION                                                             \  
        PYBIND11\_ENSURE\_INTERNALS\_READY                                                           \  
        auto m = ::pybind11::module\_::create\_extension\_module(                                    \  
            PYBIND11\_TOSTRING(name), nullptr, &PYBIND11\_CONCAT(pybind11\_module\_def\_, name));      \  
        try {                                                                                     \  
            PYBIND11\_CONCAT(pybind11\_init\_, name)(m);                                             \  
            return m.ptr();                                                                       \  
        }                                                                                         \  
        PYBIND11\_CATCH\_INIT\_EXCEPTIONS                                                            \  
    }                                                                                             \  
    void PYBIND11\_CONCAT(pybind11\_init\_, name)(::pybind11::module\_ & (variable))  

  1. 定义module_def对象。static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name);
  2. 声明init方法。static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &);
  3. 定义 PyInit_##name() 方法。创建module,并调用init方法初始化,返回PyObject*
  4. 定义init方法。void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable)) {...}

Building C and C++ Extensions

https://docs.python.org/3/extending/building.html

初始化函数有如下签名:

PyObject *PyInit_<modulename>(void)

它要么返回一个完全初始化的module,要么返回一个PyModuleDef实例。

对于只有ascii名称的模块,函数必须命名为PyInit_<modulename>,其中<modulename>被模块名称替换。当使用Multi-phase初始化时,允许使用非ascii模块名。在本例中,初始化函数名为PyInitU_<modulename>,其中<modulename>使用Python的punycode编码,连字符被下划线替换。

Initializing C modules

https://docs.python.org/3/c-api/module.html#initializing-c-modules

模块对象通常由扩展模块(导出初始化函数的共享库)或编译模块(其中初始化函数是使用PyImport_AppendInittab()添加的)创建。

初始化函数可以将模块定义实例传递给PyModule_Create(),并返回结果模块对象,或者通过返回定义结构本身来请求“多阶段初始化”。

py::module

  
// pybind11/pybind11.h  
// When inside a namespace (or anywhere as long as it's not the first item on a line),  
// C++20 allows "module" to be used. This is provided for backward compatibility, and for  
// simplicity, if someone wants to use py::module for example, that is perfectly safe.  
using module = module_;  

py::module_

  
// pybind11/pybind11.h  
/// Wrapper for Python extension modules  
class module\_ : public object {  
public:  
    PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check)  
  
    /// Create a new top-level Python module with the given name and docstring  
    PYBIND11_DEPRECATED("Use PYBIND11\_MODULE or module\_::create\_extension\_module instead")  
    explicit module\_(const char *name, const char *doc = nullptr) {  
        *this = create_extension_module(name, doc, new PyModuleDef());  
    }  
  
    /** \rst  
        Create Python binding for a new function within the module scope. ``Func``  
        can be a plain C++ function, a function pointer, or a lambda function. For  
        details on the ``Extra&& ... extra`` argument, see section :ref:`extras`.  
    \endrst */  
    template <typename Func, typename... Extra>  
    module\_ &def(const char *name\_, Func &&f, const Extra &...extra) {  
        cpp\_function func(std::forward<Func>(f),  
                          name(name\_),  
                          scope(*this),  
                          sibling(getattr(*this, name\_, none())),  
                          extra...);  
        // NB: allow overwriting here because cpp\_function sets up a chain with the intention of  
        // overwriting (and has already checked internally that it isn't overwriting  
        // non-functions).  
        add_object(name_, func, true /* overwrite */);  
        return *this;  
    }  
  
    /** \rst  
        Create and return a new Python submodule with the given name and docstring.  
        This also works recursively, i.e.  
  
        .. code-block:: cpp  
  
            py::module\_ m("example", "pybind11 example plugin");  
            py::module\_ m2 = m.def\_submodule("sub", "A submodule of 'example'");  
            py::module\_ m3 = m2.def\_submodule("subsub", "A submodule of 'example.sub'");  
    \endrst */  
    module\_ def\_submodule(const char *name, const char *doc = nullptr) {  
        const char *this_name = PyModule_GetName(m_ptr);  
        if (this_name == nullptr) {  
            throw error_already_set();  
        }  
        std::string full_name = std::string(this_name) + '.' + name;  
        handle submodule = PyImport_AddModule(full_name.c_str());  
        if (!submodule) {  
            throw error_already_set();  
        }  
        auto result = reinterpret_borrow<module_>(submodule);  
        if (doc && options::show_user_defined_docstrings()) {  
            result.attr("\_\_doc\_\_") = pybind11::str(doc);  
        }  
        attr(name) = result;  
        return result;  
    }  
  
    /// Import and return a module or throws `error\_already\_set`.  
    static module\_ import(const char *name) {  
        PyObject *obj = PyImport_ImportModule(name);  
        if (!obj) {  
            throw error_already_set();  
        }  
        return reinterpret_steal<module_>(obj);  
    }  
  
    /// Reload the module or throws `error\_already\_set`.  
    void reload() {  
        PyObject *obj = PyImport_ReloadModule(ptr());  
        if (!obj) {  
            throw error_already_set();  
        }  
        *this = reinterpret_steal<module_>(obj);  
    }  
  
    /** \rst  
        Adds an object to the module using the given name.  Throws if an object with the given name  
        already exists.  
  
        ``overwrite`` should almost always be false: attempting to overwrite objects that pybind11  
        has established will, in most cases, break things.  
    \endrst */  
    PYBIND11\_NOINLINE void add\_object(const char *name, handle obj, bool overwrite = false) {  
        if (!overwrite && hasattr(*this, name)) {  
            pybind11_fail(  
                "Error during initialization: multiple incompatible definitions with name \""  
                + std::string(name) + "\"");  
        }  
  
        PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);  
    }  
  
    using module_def = PyModuleDef; // TODO: Can this be removed (it was needed only for Python 2)?  
  
    /** \rst  
        Create a new top-level module that can be used as the main module of a C extension.  
  
        ``def`` should point to a statically allocated module\_def.  
    \endrst */  
    static module\_ create\_extension\_module(const char *name, const char *doc, module\_def *def) {  
        // module\_def is PyModuleDef  
        // Placement new (not an allocation).  
        def = new (def)  
            PyModuleDef{/* m\_base */ PyModuleDef_HEAD_INIT,  
                        /* m\_name */ name,  
                        /* m\_doc */ options::show_user_defined_docstrings() ? doc : nullptr,  
                        /* m\_size */ -1,  
                        /* m\_methods */ nullptr,  
                        /* m\_slots */ nullptr,  
                        /* m\_traverse */ nullptr,  
                        /* m\_clear */ nullptr,  
                        /* m\_free */ nullptr};  
        auto *m = PyModule_Create(def);  
        if (m == nullptr) {  
            if (PyErr_Occurred()) {  
                throw error_already_set();  
            }  
            pybind11_fail("Internal error in module\_::create\_extension\_module()");  
        }  
        // TODO: Should be reinterpret\_steal for Python 3, but Python also steals it again when  
        //       returned from PyInit\_...  
        //       For Python 2, reinterpret\_borrow was correct.  
        return reinterpret_borrow<module_>(m);  
    }  
};  

https://docs.python.org/3/c-api/module.html#c.PyModuleDef

  
// include/python3.9/moduleobject.h  
typedef struct PyModuleDef{  
  PyModuleDef_Base m_base;  
  const char* m_name;  
  const char* m_doc;  
  Py_ssize_t m_size;  
  PyMethodDef *m_methods;  
  struct PyModuleDef\_Slot* m\_slots;  
  traverseproc m_traverse;  
  inquiry m_clear;  
  freefunc m_free;  
} PyModuleDef;  

  
// include/python3.9/moduleobject.h  
PyAPI_DATA(PyTypeObject) PyModule_Type;  
  
#define PyModule\_Check(op) PyObject\_TypeCheck(op, &PyModule\_Type)  

  
// include/python3.9/import.h  
PyAPI_FUNC(PyObject *) PyImport_AddModule(  
    const char *name            /* UTF-8 encoded string */  
    );  
PyAPI_FUNC(PyObject *) PyImport_ImportModule(  
    const char *name            /* UTF-8 encoded string */  
    );  

py::object

py::object 类继承自 py::handle 并添加自动引用计数功能。

  
// pybind11/pytypes.h  
/** \rst  
    Holds a reference to a Python object (with reference counting)  
  
    Like `handle`, the `object` class is a thin wrapper around an arbitrary Python  
    object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it  
    optionally increases the object's reference count upon construction, and it  
    *always* decreases the reference count when the `object` instance goes out of  
    scope and is destructed. When using `object` instances consistently, it is much  
    easier to get reference counting right at the first attempt.  
\endrst */  
class object : public handle {  
public:  
    object() = default;  
    PYBIND11_DEPRECATED("Use reinterpret\_borrow<object>() or reinterpret\_steal<object>()")  
    object(handle h, bool is_borrowed) : handle(h) {  
        if (is_borrowed) {  
            inc_ref();  
        }  
    }  
    /// Copy constructor; always increases the reference count  
    object(const object &o) : handle(o) { inc_ref(); }  
    /// Move constructor; steals the object from ``other`` and preserves its reference count  
    object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; }  
    /// Destructor; automatically calls `handle::dec\_ref()`  
    ~object() { dec_ref(); }  
  
    /** \rst  
        Resets the internal pointer to ``nullptr`` without decreasing the  
        object's reference count. The function returns a raw handle to the original  
        Python object.  
    \endrst */  
    handle release() {  
        PyObject *tmp = m_ptr;  
        m_ptr = nullptr;  
        return handle(tmp);  
    }  
  
    object &operator=(const object &other) {  
        // Skip inc\_ref and dec\_ref if both objects are the same  
        if (!this->is(other)) {  
            other.inc_ref();  
            // Use temporary variable to ensure `*this` remains valid while  
            // `Py\_XDECREF` executes, in case `*this` is accessible from Python.  
            handle temp(m\_ptr);  
            m_ptr = other.m_ptr;  
            temp.dec_ref();  
        }  
        return *this;  
    }  
  
    object &operator=(object &&other) noexcept {  
        if (this != &other) {  
            handle temp(m_ptr);  
            m_ptr = other.m_ptr;  
            other.m_ptr = nullptr;  
            temp.dec_ref();  
        }  
        return *this;  
    }  
  
#define PYBIND11\_INPLACE\_OP(iop)                                                                  \  
    object iop(object\_api const &other) { return operator=(handle::iop(other)); }  
  
    PYBIND11_INPLACE_OP(operator+=)  
    PYBIND11_INPLACE_OP(operator-=)  
    PYBIND11_INPLACE_OP(operator*=)  
    PYBIND11_INPLACE_OP(operator/=)  
    PYBIND11_INPLACE_OP(operator|=)  
    PYBIND11_INPLACE_OP(operator&=)  
    PYBIND11_INPLACE_OP(operator^=)  
    PYBIND11_INPLACE_OP(operator<<=)  
    PYBIND11_INPLACE_OP(operator>>=)  
#undef PYBIND11\_INPLACE\_OP  
  
    // Calling cast() on an object lvalue just copies (via handle::cast)  
    template <typename T>  
    T cast() const &;  
    // Calling on an object rvalue does a move, if needed and/or possible  
    template <typename T>  
    T cast() &&;  
  
protected:  
    // Tags for choosing constructors from raw PyObject *  
    struct borrowed\_t {};  
    struct stolen\_t {};  
  
    /// @cond BROKEN  
    template <typename T>  
    friend T reinterpret\_borrow(handle);  
    template <typename T>  
    friend T reinterpret\_steal(handle);  
    /// @endcond  
  
public:  
    // Only accessible from derived classes and the reinterpret\_* functions  
    object(handle h, borrowed\_t) : handle(h) { inc_ref(); }  
    object(handle h, stolen\_t) : handle(h) {}  
};  

py::handle

持有 PyObject *m_ptr = nullptr; 对象。

py::handle 类是对任意Python对象(即 Python C API中的 PyObject* )。它不执行任何自动引用,并且仅仅提供了一个基本的c++接口来处理各种Python API函数。

  
// pybind11/pytypes.h  
/** \rst  
    Holds a reference to a Python object (no reference counting)  
  
    The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a  
    ``PyObject *`` in Python's C API). It does not perform any automatic reference  
    counting and merely provides a basic C++ interface to various Python API functions.  
  
    .. seealso::  
        The `object` class inherits from `handle` and adds automatic reference  
        counting features.  
\endrst */  
class handle : public detail::object_api<handle> {  
public:  
    /// The default constructor creates a handle with a ``nullptr``-valued pointer  
    handle() = default;  
  
    /// Enable implicit conversion from ``PyObject *`` and ``nullptr``.  
    /// Not using ``handle(PyObject *ptr)`` to avoid implicit conversion from ``0``.  
    template <typename T,  
              detail::enable\_if\_t<detail::is\_pyobj\_ptr\_or\_nullptr\_t<T>::value, int> = 0>  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    handle(T ptr) : m_ptr(ptr) {}  
  
    /// Enable implicit conversion through ``T::operator PyObject *()``.  
    template <  
        typename T,  
        detail::enable\_if\_t<detail::all_of<detail::none_of<std::is_base_of<handle, T>,  
                                                           detail::is\_pyobj\_ptr\_or\_nullptr\_t<T>>,  
                                           std::is_convertible<T, PyObject *>>::value,  
                            int>  
        = 0>  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    handle(T &obj) : m_ptr(obj) {}  
  
    /// Return the underlying ``PyObject *`` pointer  
    PyObject *ptr() const { return m_ptr; }  
    PyObject *&ptr() { return m_ptr; }  
  
    /** \rst  
        Manually increase the reference count of the Python object. Usually, it is  
        preferable to use the `object` class which derives from `handle` and calls  
        this function automatically. Returns a reference to itself.  
    \endrst */  
    const handle &inc\_ref() const & {  
#ifdef PYBIND11\_HANDLE\_REF\_DEBUG  
        inc_ref_counter(1);  
#endif  
#ifdef PYBIND11\_ASSERT\_GIL\_HELD\_INCREF\_DECREF  
        if (m_ptr != nullptr && !PyGILState_Check()) {  
            throw_gilstate_error("pybind11::handle::inc\_ref()");  
        }  
#endif  
        Py_XINCREF(m_ptr);  
        return *this;  
    }  
  
    /** \rst  
        Manually decrease the reference count of the Python object. Usually, it is  
        preferable to use the `object` class which derives from `handle` and calls  
        this function automatically. Returns a reference to itself.  
    \endrst */  
    const handle &dec\_ref() const & {  
#ifdef PYBIND11\_ASSERT\_GIL\_HELD\_INCREF\_DECREF  
        if (m_ptr != nullptr && !PyGILState_Check()) {  
            throw_gilstate_error("pybind11::handle::dec\_ref()");  
        }  
#endif  
        Py_XDECREF(m_ptr);  
        return *this;  
    }  
  
    /** \rst  
        Attempt to cast the Python object into the given C++ type. A `cast\_error`  
        will be throw upon failure.  
    \endrst */  
    template <typename T>  
    T cast() const;  
    /// Return ``true`` when the `handle` wraps a valid Python object  
    explicit operator bool() const { return m_ptr != nullptr; }  
    /** \rst  
        Deprecated: Check that the underlying pointers are the same.  
        Equivalent to ``obj1 is obj2`` in Python.  
    \endrst */  
    PYBIND11_DEPRECATED("Use obj1.is(obj2) instead")  
    bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }  
    PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead")  
    bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }  
    PYBIND11_DEPRECATED("Use handle::operator bool() instead")  
    bool check() const { return m_ptr != nullptr; }  
  
protected:  
    PyObject *m_ptr = nullptr;  
  
private:  
#ifdef PYBIND11\_ASSERT\_GIL\_HELD\_INCREF\_DECREF  
    void throw\_gilstate\_error(const std::string &function\_name) const {  
        fprintf(  
            stderr,  
            "%s is being called while the GIL is either not held or invalid. Please see "  
            "https://pybind11.readthedocs.io/en/stable/advanced/"  
            "misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.\n",  
            function_name.c_str());  
        fflush(stderr);  
        if (Py_TYPE(m_ptr)->tp_name != nullptr) {  
            fprintf(stderr,  
                    "The failing %s call was triggered on a %s object.\n",  
                    function_name.c_str(),  
                    Py_TYPE(m_ptr)->tp_name);  
            fflush(stderr);  
        }  
        throw std::runtime_error(function_name + " PyGILState\_Check() failure.");  
    }  
#endif  
  
#ifdef PYBIND11\_HANDLE\_REF\_DEBUG  
    static std::size\_t inc\_ref\_counter(std::size\_t add) {  
        thread\_local std::size\_t counter = 0;  
        counter += add;  
        return counter;  
    }  
  
public:  
    static std::size\_t inc\_ref\_counter() { return inc_ref_counter(0); }  
#endif  
};  

py::object_api

  
// pybind11/pytypes.h  
/// Tag and check to identify a class which implements the Python object API  
class pyobject\_tag {};  
template <typename T>  
using is_pyobject = std::is_base_of<pyobject_tag, remove\_reference\_t<T>>;  
  
  
template <typename T>  
using is\_pyobj\_ptr\_or\_nullptr\_t = detail::any_of<std::is_same<T, PyObject *>,  
                                                 std::is_same<T, PyObject *const>,  
                                                 std::is_same<T, std::nullptr\_t>>;  

  
// pybind11/pytypes.h  
/** \rst  
    A mixin class which adds common functions to `handle`, `object` and various accessors.  
    The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``.  
\endrst */  
template <typename Derived>  
class object\_api : public pyobject_tag {  
    const Derived &derived() const { return static\_cast<const Derived &>(*this); }  
  
public:  
    /** \rst  
        Return an iterator equivalent to calling ``iter()`` in Python. The object  
        must be a collection which supports the iteration protocol.  
    \endrst */  
    iterator begin() const;  
    /// Return a sentinel which ends iteration.  
    iterator end() const;  
  
    /** \rst  
        Return an internal functor to invoke the object's sequence protocol. Casting  
        the returned ``detail::item\_accessor`` instance to a `handle` or `object`  
        subclass causes a corresponding call to ``\_\_getitem\_\_``. Assigning a `handle`  
        or `object` subclass causes a call to ``\_\_setitem\_\_``.  
    \endrst */  
    item_accessor operator[](handle key) const;  
    /// See above (the only difference is that the key's reference is stolen)  
    item_accessor operator[](object &&key) const;  
    /// See above (the only difference is that the key is provided as a string literal)  
    item_accessor operator[](const char *key) const;  
  
    /** \rst  
        Return an internal functor to access the object's attributes. Casting the  
        returned ``detail::obj\_attr\_accessor`` instance to a `handle` or `object`  
        subclass causes a corresponding call to ``getattr``. Assigning a `handle`  
        or `object` subclass causes a call to ``setattr``.  
    \endrst */  
    obj\_attr\_accessor attr(handle key) const;  
    /// See above (the only difference is that the key's reference is stolen)  
    obj\_attr\_accessor attr(object &&key) const;  
    /// See above (the only difference is that the key is provided as a string literal)  
    str\_attr\_accessor attr(const char *key) const;  
  
    /** \rst  
        Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``  
        or ``list`` for a function call. Applying another * to the result yields  
        ** unpacking, e.g. to unpack a dict as function keyword arguments.  
        See :ref:`calling\_python\_functions`.  
    \endrst */  
    args_proxy operator*() const;  
  
    /// Check if the given item is contained within this object, i.e. ``item in obj``.  
    template <typename T>  
    bool contains(T &&item) const;  
  
    /** \rst  
        Assuming the Python object is a function or implements the ``\_\_call\_\_``  
        protocol, ``operator()`` invokes the underlying function, passing an  
        arbitrary set of parameters. The result is returned as a `object` and  
        may need to be converted back into a Python object using `handle::cast()`.  
  
        When some of the arguments cannot be converted to Python objects, the  
        function will throw a `cast\_error` exception. When the Python function  
        call fails, a `error\_already\_set` exception is thrown.  
    \endrst */  
    template <return_value_policy policy = return_value_policy::automatic_reference,  
              typename... Args>  
    object operator()(Args &&...args) const;  
    template <return_value_policy policy = return_value_policy::automatic_reference,  
              typename... Args>  
    PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")  
    object call(Args &&...args) const;  
  
    /// Equivalent to ``obj is other`` in Python.  
    bool is(object\_api const &other) const { return derived().ptr() == other.derived().ptr(); }  
    /// Equivalent to ``obj is None`` in Python.  
    bool is\_none() const { return derived().ptr() == Py_None; }  
    /// Equivalent to obj == other in Python  
    bool equal(object\_api const &other) const { return rich_compare(other, Py_EQ); }  
    bool not\_equal(object\_api const &other) const { return rich_compare(other, Py_NE); }  
    bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); }  
    bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); }  
    bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); }  
    bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); }  
  
    object operator-() const;  
    object operator~() const;  
    object operator+(object_api const &other) const;  
    object operator+=(object_api const &other);  
    object operator-(object_api const &other) const;  
    object operator-=(object_api const &other);  
    object operator*(object_api const &other) const;  
    object operator*=(object_api const &other);  
    object operator/(object_api const &other) const;  
    object operator/=(object_api const &other);  
    object operator|(object_api const &other) const;  
    object operator|=(object_api const &other);  
    object operator&(object_api const &other) const;  
    object operator&=(object_api const &other);  
    object operator^(object_api const &other) const;  
    object operator^=(object_api const &other);  
    object operator<<(object_api const &other) const;  
    object operator<<=(object_api const &other);  
    object operator>>(object_api const &other) const;  
    object operator>>=(object_api const &other);  
  
    PYBIND11_DEPRECATED("Use py::str(obj) instead")  
    pybind11::str str() const;  
  
    /// Get or set the object's docstring, i.e. ``obj.\_\_doc\_\_``.  
    str\_attr\_accessor doc() const;  
  
    /// Return the object's current reference count  
    int ref\_count() const { return static\_cast<int>(Py_REFCNT(derived().ptr())); }  
  
    // TODO PYBIND11\_DEPRECATED(  
    //     "Call py::type::handle\_of(h) or py::type::of(h) instead of h.get\_type()")  
    handle get\_type() const;  
  
private:  
    bool rich\_compare(object\_api const &other, int value) const;  
};  

py::cpp_function

  
// pybind11/pybind11.h  
// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object  
class cpp\_function : public function {  
public:  
    cpp_function() = default;  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    cpp_function(std::nullptr\_t) {}  
  
    /// Construct a cpp\_function from a vanilla function pointer  
    template <typename Return, typename... Args, typename... Extra>  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    cpp_function(Return (*f)(Args...), const Extra &...extra) {  
        initialize(f, f, extra...);  
    }  
  
    /// Construct a cpp\_function from a lambda function (possibly with internal state)  
    template <typename Func,  
              typename... Extra,  
              typename = detail::enable\_if\_t<detail::is_lambda<Func>::value>>  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    cpp_function(Func &&f, const Extra &...extra) {  
        initialize(  
            std::forward<Func>(f), (detail::function\_signature\_t<Func> *) nullptr, extra...);  
    }  
  
    /// Construct a cpp\_function from a class method (non-const, no ref-qualifier)  
    template <typename Return, typename Class, typename... Arg, typename... Extra>  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    cpp_function(Return (Class::*f)(Arg...), const Extra &...extra) {  
        initialize(  
            [f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },  
            (Return(*)(Class *, Arg...)) nullptr,  
            extra...);  
    }  
  
    /// Construct a cpp\_function from a class method (non-const, lvalue ref-qualifier)  
    /// A copy of the overload for non-const functions without explicit ref-qualifier  
    /// but with an added `&`.  
    template <typename Return, typename Class, typename... Arg, typename... Extra>  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    cpp_function(Return (Class::*f)(Arg...) &, const Extra &...extra) {  
        initialize(  
            [f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },  
            (Return(*)(Class *, Arg...)) nullptr,  
            extra...);  
    }  
  
    /// Construct a cpp\_function from a class method (const, no ref-qualifier)  
    template <typename Return, typename Class, typename... Arg, typename... Extra>  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    cpp_function(Return (Class::*f)(Arg...) const, const Extra &...extra) {  
        initialize([f](const Class *c,  
                       Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },  
                   (Return(*)(const Class *, Arg...)) nullptr,  
                   extra...);  
    }  
  
    /// Construct a cpp\_function from a class method (const, lvalue ref-qualifier)  
    /// A copy of the overload for const functions without explicit ref-qualifier  
    /// but with an added `&`.  
    template <typename Return, typename Class, typename... Arg, typename... Extra>  
    // NOLINTNEXTLINE(google-explicit-constructor)  
    cpp_function(Return (Class::*f)(Arg...) const &, const Extra &...extra) {  
        initialize([f](const Class *c,  
                       Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },  
                   (Return(*)(const Class *, Arg...)) nullptr,  
                   extra...);  
    }  
  
    /// Return the function name  
    object name() const { return attr("\_\_name\_\_"); }  
  ...    
};  

py::function

  
// pybind11/pytypes.h  
class function : public object {  
public:  
    PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check)  
    handle cpp\_function() const {  
        handle fun = detail::get_function(m_ptr);  
        if (fun && PyCFunction_Check(fun.ptr())) {  
            return fun;  
        }  
        return handle();  
    }  
    bool is\_cpp\_function() const { return (bool) cpp_function(); }  
};  

  
// python3.9/object.h  
PyAPI_FUNC(int) PyCallable_Check(PyObject *);  

  
// pybind11/pytypes.h  
inline handle get\_function(handle value) {  
    if (value) {  
        if (PyInstanceMethod_Check(value.ptr())) {  
            value = PyInstanceMethod_GET_FUNCTION(value.ptr());  
        } else if (PyMethod_Check(value.ptr())) {  
            value = PyMethod_GET_FUNCTION(value.ptr());  
        }  
    }  
    return value;  
}  

  
// python3.9/classobject.h  
PyAPI_DATA(PyTypeObject) PyMethod_Type;  
  
#define PyMethod\_Check(op) Py\_IS\_TYPE(op, &PyMethod\_Type)  
  
PyAPI_DATA(PyTypeObject) PyInstanceMethod_Type;  
  
#define PyInstanceMethod\_Check(op) Py\_IS\_TYPE(op, &PyInstanceMethod\_Type)  

参考文献

picture.image

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
云原生可观测性技术的落地实践
云原生技术和理念在近几年成为了备受关注的话题。应用通过云原生改造,变得更动态、弹性,可以更好地利用云的弹性能力。但是动态、弹性的环境也给应用以及基础设施的观测带来了更大的挑战。本次分享主要介绍了云原生社区中可观测性相关的技术和工具,以及如何使用这些工具来完成对云原生环境的观测。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论