通过 C++ pythonization 回调将 operator() 的 cppyy 自动映射恢复到 __getitem__

Posted

技术标签:

【中文标题】通过 C++ pythonization 回调将 operator() 的 cppyy 自动映射恢复到 __getitem__【英文标题】:Revert cppyy automatic mapping of operator() to __getitem__ via C++ pythonization callback 【发布时间】:2021-02-17 13:56:18 【问题描述】:

正如this cppyy issue 中所解释的,C++ 端的A& operator() 映射到python __getitem__

如果这不是想要的结果,建议添加一个特殊的pythonization。

在我的例子中,一个额外的限制是将它添加到 C++ 类本身,以确保始终应用这个 python 化。

但是,我无法弄清楚如何通过 Python C API 正确执行此操作。 (第一次使用该 API,所以我有点迷茫)

Minimal Reproducer 有点做作,但显示了问题:注意在下面的示例中,struct A 是我无法修改的代码,因为该类是在库代码中定义的。所以回调必须在B中。

import cppyy


cppyy.include("Python.h")

cppyy.cppdef(r"""

void myprint(PyObject* py)
    PyObject* tmp = PyObject_Str(py);
    Py_ssize_t size = 0;
    const char* s = PyUnicode_AsUTF8AndSize(tmp, &size);
    std::cout << std::string(s, size) << std::endl;


template <typename T>
struct A 
  T& operator[](size_t idx)  return arr[idx]; 
  const T& operator[](size_t idx) const  return arr[idx]; 
  std::array<T, 10> arr;
;

template <typename T>
struct B : public A<T> 
  B& operator()()  return *this; ;

  static void __cppyy_pythonize__( PyObject* klass, const std::string& name)
    std::cout << "Hello from pythonize" << std::endl;

    PyObject* getitem = PyObject_GetAttrString(klass, "__getitem__");

    myprint(getitem);
  
;


using tmp = B<double>;
""")


t = cppyy.gbl.B['double']
print(t.__getitem__.__doc__)

我可以从 PyObject* klass 获取 __getitem__ 函数,但是,正如文档中所解释的,回调发生在类的所有内部处理之后的最后。 因此__call__ 函数,这里是B&amp; operator()(),已经映射到__getitem__

不幸的是,我一生都无法弄清楚如何撤消该映射并取回旧的__getitem__ 函数。 operator[]() 功能是否仍然可以通过 PyObject* klass 访问?

任何帮助/指针将不胜感激:)

【问题讨论】:

【参考方案1】:

首先,回答你的问题,找到你想要的__getitem__,从klass的基类中获取,而不是直接从klass获取。您也可以在 Python 中执行此操作,而不是在 C++ 中添加 python 化。事实上,最好在 Python 中执行此操作,因为这样您就不必处理 C-API。

但是,由于实际的错误报告不是您引用的错误报告,而是 this one,并且由于您在此处遵循的那里提出的建议使这是一个经典的 XY 问题,所以我还要补充一下您真正的问题想要在你的代码示例中简单地做PyObject_DelAttrString(klass, "__getitem__")

完全不说,这里给您带来麻烦的代码来自 Gaudi 项目,该项目的核心开发人员是最开始要求这种自动映射的人。你可能想和他们一起解决这个问题。

【讨论】:

非常感谢 Wim 的快速回复!我想在 C-API 中执行此操作的原因是我没有看到一种使用 Python 全局执行此操作的方法。此外,最后它似乎不是一个复杂的解决方案!只是觉得我现在有更多问题,因为我不清楚为什么会这样 :D 无论如何,再次感谢您抽出时间回复并解决我的问题 :)

以上是关于通过 C++ pythonization 回调将 operator() 的 cppyy 自动映射恢复到 __getitem__的主要内容,如果未能解决你的问题,请参考以下文章

python ctypes,回调函数增广类型为C++参考

将 python 函数传递给 SWIG 包装的 C++ 代码

使用 boost::python 将回调从 python 传递到 c++

将 python + numpy 代码嵌入到 C++ dll 回调中

来自 C++ 的回调 python 函数,对象被破坏

从 Python 将不透明数据传递给 C++ 回调