【问题标题】:How to include __build_class__ when creating a module in the python C API在 python C API 中创建模块时如何包含 __build_class__
【发布时间】:2017-02-20 23:37:39
【问题描述】:

我正在尝试使用Python 3.5 C API 来执行一些包括构造类的代码。具体如下:

class MyClass:
    def test(self):
        print('test')

MyClass().test()

我遇到的问题是这样的错误:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: __build_class__ not found

所以不知何故,我需要我的模块包含__build_class__,但我不确定如何(我想我也会错过使用Python 时默认获得的其他东西) - 有没有办法包含所有我的模块中有这个内置的东西吗?

到目前为止,这是我的代码:

#include <Python.h>

int main(void)
{
    int ret = 0;
    PyObject *pValue, *pModule, *pGlobal, *pLocal;

    Py_Initialize();

    pGlobal = PyDict_New();
    pModule = PyModule_New("mymod");
    pLocal = PyModule_GetDict(pModule);

    pValue = PyRun_String(
        "class MyClass:\n\tdef test(self):\n\t\tprint('test')\n\nMyClass().test()",
        Py_file_input,
        pGlobal,
        pLocal);

    if (pValue == NULL) {
        if (PyErr_Occurred()) {
            PyErr_Print();
        }
        ret = 1;
    } else {
        Py_DECREF(pValue);
    }

    Py_Finalize();

    return ret;
}

所以pValueNULL,它正在调用PyErr_Print

【问题讨论】:

  • 我认为您需要将解释器全局变量而不是空字典传递给它。但我不知道该怎么做。
  • 谢谢,遗憾的是 PyEval_GetGlobals();返回 null (我从调用中得到 SystemError: PyEval_EvalCodeEx: NULL globals)。我是否需要导入 main 模块或类似的东西?
  • 啊,感谢您的提示,我开始寻找 GetGlobals 返回 null 并发现:gossamer-threads.com/lists/python/python/8946#8946 - 似乎我需要执行 pGlobal = PyModule_GetDict(PyImport_AddModule("main ")); (而不是 pGlobal = PyDict_New())然后它就可以工作了。 (主要有下划线,不是粗体)谢谢!
  • 很高兴为您指明了正确的方向。 (我不确定我自己是否会得到有用的答案)。顺便说一句,您可以将代码放在带有反引号(`)的cmets中

标签: python c python-3.x python-c-api


【解决方案1】:

他们似乎(至少)有两种方法可以解决这个问题......

方式 1

代替:

pGlobal = PyDict_New();

您可以像这样导入__main__ 模块并获取它的全局字典:

pGlobal = PyModule_GetDict(PyImport_AddModule("__main__"));

这种方式是这样描述的:

但是 PyEval_GetGlobals 将返回 null 它不是从内部调用的 Python。在扩展 Python 时永远不会出现这种情况,但是当 Python 是嵌入式的,它可能会发生。这是因为 PyRun_* 定义了全局 范围,因此,如果您不在 PyRun_ 事物中(例如,名为 从嵌入器调用的python),没有全局变量。

在嵌入式 python 情况下,如果您决定将所有 PyRun_* 调用将使用__main__ 作为全局命名空间, PyModule_GetDict(PyImport_AddModule("__main__")) 会做到的。

我从问题embedding 中得到的答案是我在这个Python list 上找到的。

方式 2

或者作为替代方案,我个人更喜欢导入主模块(并找到here),您可以这样做以使用包含__build_class__的内置内容填充您创建的新字典:

pGlobal = PyDict_New();
PyDict_SetItemString(pGlobal, "__builtins__", PyEval_GetBuiltins());

【讨论】:

    猜你喜欢
    • 2012-01-09
    • 2016-10-03
    • 1970-01-01
    • 2021-10-21
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多