如何从C扩展中定义Python元类?
在纯Python中,定义和使用元类相对简单如何从C扩展中定义Python元类?,python,cpython,metaclass,python-extensions,Python,Cpython,Metaclass,Python Extensions,在纯Python中,定义和使用元类相对简单 class Meta(type): def __new__(cls, name, bases, dict): x = super().__new__(cls, name, bases, dict) print("I'm called on class construction time!") return x class A(metaclass=Meta): pass
class Meta(type):
def __new__(cls, name, bases, dict):
x = super().__new__(cls, name, bases, dict)
print("I'm called on class construction time!")
return x
class A(metaclass=Meta):
pass
class B(A):
pass
如何从Python C扩展中定义这个元类?- 定义
PyType\u Type
- 在
tp\u init
- 通过在
PyVarObject\u HEAD\u INIT
#包括
#包括
结构foometa{
PyTypeObject头;
};
int foometa_init(foometa*cls、PyObject*args、PyObject*kwargs){
if(PyType_Type.tp_init((PyObject*)cls、args、kwargs)<0){
返回-1;
}
标准:cerr tp_alloc(类型,0);
返回obj;
}
静态PyTypeObject FoopParent\u类型={
PyVarObject\u HEAD\u INIT(&foometa\u类型,0)
“demo.fooparent”,
sizeof(PyObject),
0,
0,/*tp_dealoc*/
0,/*tp_打印*/
0,/*tp\u getattr*/
0,/*tp_setattr*/
0,/*tp_保留*/
0,/*tp_repr*/
0,/*tp\U作为\U编号*/
0,/*tp\u作为\u序列*/
0,/*tp_作为映射*/
0,/*tp_散列*/
0,/*tp\u调用*/
0,/*tp_str*/
0,/*tp_getattro*/
0,/*tp_setattro*/
0,/*tp作为缓冲区*/
Py_TPFLAGS|Py_TPFLAGS|BASETYPE,/*tp_标志*/
0,/*tp_文件*/
0,/*tp\u导线测量*/
0,/*tp_清除*/
0,/*tp_*/
0,/*tp_弱偏移*/
0,/*tp_iter*/
0,/*tp_iternext*/
0,/*tp_方法*/
0,/*tp_成员*/
0,/*tp\u getset*/
0,/*tp_基*/
0,/*tp_dict*/
0,/*tp\u descr\u get*/
0,/*tp\u descr\u集*/
0,/*tp\u偏移量*/
0,/*tp_init*/
0,/*tp_alloc*/
fooparent_new/*tp_new*/
};
int
demo_init(PyObject*m){
foometa_type.tp_base=&PyType_type;
if(PyType_Ready(&foometa_type)<0){
返回-1;
}
if(PyType\u Ready(&foopparent\u type)<0){
返回-1;
}
Py_增量(&foometa_类型);
if(PyModule_AddObject)(m,“foometa”,
(PyObject*)和Foomata_类型)<0)
返回-1;
Py_增量(&fooparent_类型);
if(PyModule_AddObject)(m,“fooparent”,
(PyObject*)和fooparent_类型)<0)
返回-1;
返回0;
}
静态PyModuleDef demomodule={
PyModuleDef_HEAD_INIT,
“演示”,
“示例模块”,
-1,
空,空,空,空,空,空
};
PyMODINIT_FUNC
PyInit_demo(){
PyObject*m=PyModule\u创建(&demomodule);
如果(m==nullptr),则返回nullptr;
if(demo_init(m)<0)返回nullptr;
返回m;
}
完整示例runnable at在这段代码中有一个bug,如果你从fooparent子类化两次,你将使assert
Modules/gcmodule失败。c:714:handle_weakrefs:Assertion“wr->wr_object==op”失败
bug已经修复,我认为。foometa结构没有足够的字段,有趣的是,因此它的定义可能是错误的。tp_init
是与\uuu init\uuu
等价的C,而不是\uu new\uu
<代码>\uuuuuuuuuuuuuuuuuuuuuuu逻辑应进入tp\u new
。
#include <Python.h>
#include <iostream>
struct foometa {
PyTypeObject head;
};
int foometa_init(foometa *cls, PyObject *args, PyObject *kwargs) {
if (PyType_Type.tp_init((PyObject*)cls, args, kwargs) < 0) {
return -1;
}
std::cerr << "I'm called on class construction time!\n";
return 0;
}
#define DEFERRED_ADDRESS(ADDR) nullptr
static PyTypeObject foometa_type = {
PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
"demo.foometa",
0,
0,
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 | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
DEFERRED_ADDRESS(&PyType_Type), /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)foometa_init, /* tp_init */
0, /* tp_alloc */
0 /* tp_new */
};
PyObject *fooparent_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject* obj = type->tp_alloc(type, 0);
return obj;
}
static PyTypeObject fooparent_type = {
PyVarObject_HEAD_INIT(&foometa_type, 0)
"demo.fooparent",
sizeof(PyObject),
0,
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 | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
fooparent_new /* tp_new */
};
int
demo_init(PyObject *m) {
foometa_type.tp_base = &PyType_Type;
if (PyType_Ready(&foometa_type) < 0) {
return -1;
}
if (PyType_Ready(&fooparent_type) < 0) {
return -1;
}
Py_INCREF(&foometa_type);
if (PyModule_AddObject(m, "foometa",
(PyObject *) &foometa_type) < 0)
return -1;
Py_INCREF(&fooparent_type);
if (PyModule_AddObject(m, "fooparent",
(PyObject *) &fooparent_type) < 0)
return -1;
return 0;
}
static PyModuleDef demomodule = {
PyModuleDef_HEAD_INIT,
"demo",
"Example module",
-1,
NULL, NULL, NULL, NULL, NULL
};
PyMODINIT_FUNC
PyInit_demo() {
PyObject* m = PyModule_Create(&demomodule);
if (m == nullptr) return nullptr;
if (demo_init(m) < 0) return nullptr;
return m;
}