通过 C++ pythonization 回调将 operator() 的 cppyy 自动映射还原为 __getitem__

Revert cppyy automatic mapping of operator() to __getitem__ via C++ pythonization callback

this cppyy issue 中所述,C++ 端的 A& operator() 映射到 python __getitem__.

在这个问题上,如果这不是想要的结果,建议添加一个特殊的python化。

在我的例子中,一个额外的约束是将其添加到 C++ class 本身,以确保始终应用此 pythonization。

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

Minimal Reproducer 有点做作但显示了问题:
注意 在下面的示例中 struct A 是我无法修改的代码,因为 class 是在库代码中定义的。所以回调必须在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__ 函数,但是,如文档中所述,回调发生在 class 的所有内部处理之后的最后。
因此 __call__ 函数,这里是 B& operator()(),已经被映射到 __getitem__.

不幸的是,我这辈子都想不出如何撤消该映射并取回旧的 __getitem__ 函数。 operator[]() 函数是否仍然可以通过 PyObject* klass 访问?

任何help/pointers将不胜感激:)

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

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

不说了,给你添麻烦的代码来自于高迪项目,这个项目的核心开发者就是第一个提出这个自动映射需求的人。你可能想和他们一起解决这个问题。