【问题标题】:Python C/API: how to create a normal classPython C/API:如何创建普通类
【发布时间】:2017-02-18 21:39:47
【问题描述】:

使用 Python C/API,如何使用普通 Python 类创建机制(即:不是扩展类型)创建普通 Python 类?

换句话说,一个语句的 Python C/API 等价物是什么(在某种意义上它完全在所有情况下都一样)

class X(bases):
    ...some methods/attributes here...

【问题讨论】:

    标签: python class python-c-api


    【解决方案1】:

    在 Python 中,您可以通过调用 type 内置函数以编程方式创建一个类。例如,请参阅this answer

    这需要三个参数:名称、基元组和字典。

    您可以在 C api 中以PyType_Type 的形式获取 Python type。然后你只需要使用one of the standard methods for calling PyObject* callables调用它:

    // make a tuple of your bases
    PyObject* bases = PyTuple_Pack(0); // assume no bases
    // make a dictionary of member functions, etc
    PyObject* dict = PyDict_New(); // empty for the sake of example 
    PyObject* my_new_class = PyObject_CallFunction(&PyType_Type,"sOO",
                                                 "X", // class name
                                                 bases,
                                                 dict);
    // check if null
    
    // decref bases and dict
    Py_CLEAR(bases);
    Py_CLEAR(dict);
    

    (请注意,您必须这样做 &PyType_Type - 文档暗示它是 PyObject* 但它不是!)

    【讨论】:

    • 谢谢,这似乎有效。虽然我想知道如果涉及元类,“class Derived(Base): pass”是否真的 100% 等同于“Derived = type("Derived", (Base,), {})"。
    • 我相信如果涉及元类,您应该致电Derived = metaclass("Derived", (Base,), {})。但是,这稍微超出了我的实际确定范围......
    • 作为一个额外的东西 - 你看到这个mail.python.org/pipermail/python-dev/2009-July/090921.html了吗?看起来确实有第二种方法涉及自己分配PyTypeObjects(但似乎没有人喜欢它......)
    【解决方案2】:

    我不确定您所说的“正常的 Python 类创建机制”是什么意思,但是...

    有一个专门的文档页面:https://docs.python.org/3/extending/newtypes.html——它在扩展模块中创建一个新类型,相当于在 Python 代码中创建一个新的class

    这里给出的最小示例是:

    #include <Python.h>
    
    typedef struct {
        PyObject_HEAD
        /* Type-specific fields go here. */
    } noddy_NoddyObject;
    
    static PyTypeObject noddy_NoddyType = {
        PyVarObject_HEAD_INIT(NULL, 0)
        "noddy.Noddy",             /* tp_name */
        sizeof(noddy_NoddyObject), /* tp_basicsize */
        0,                         /* tp_itemsize */
        0,                         /* tp_dealloc */
        0,                         /* tp_print */
        0,                         /* tp_getattr */
        0,                         /* tp_setattr */
        0,                         /* tp_reserved */
        0,                         /* tp_repr */
        0,                         /* tp_as_number */
        0,                         /* tp_as_sequence */
        0,                         /* tp_as_mapping */
        0,                         /* tp_hash  */
        0,                         /* tp_call */
        0,                         /* tp_str */
        0,                         /* tp_getattro */
        0,                         /* tp_setattro */
        0,                         /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT,        /* tp_flags */
        "Noddy objects",           /* tp_doc */
    };
    
    static PyModuleDef noddymodule = {
        PyModuleDef_HEAD_INIT,
        "noddy",
        "Example module that creates an extension type.",
        -1,
        NULL, NULL, NULL, NULL, NULL
    };
    
    PyMODINIT_FUNC
    PyInit_noddy(void)
    {
        PyObject* m;
    
        noddy_NoddyType.tp_new = PyType_GenericNew;
        if (PyType_Ready(&noddy_NoddyType) < 0)
            return NULL;
    
        m = PyModule_Create(&noddymodule);
        if (m == NULL)
            return NULL;
    
        Py_INCREF(&noddy_NoddyType);
        PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType);
        return m;
    }
    

    【讨论】:

    • 这正是我不想要的。我不想要扩展类型,而只是在运行时创建的 Python 类。
    • @JeroenDemeyer:您的问题说“Python C/API 相当于类似语句”,所以这就是我所理解的。请考虑重新表述您的问题以更清楚。
    • 我的意思是最字面意义上的“等效”。我不是说“相似”,我是说“完全一样”。
    猜你喜欢
    • 1970-01-01
    • 2010-09-27
    • 2011-12-25
    • 1970-01-01
    • 2012-01-09
    • 1970-01-01
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多