-
Notifications
You must be signed in to change notification settings - Fork 803
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Add way to set metaclass for #[pyclass] #906
Comments
Has there been progress on this issue? I'm looking for a way of implementing a custom instancecheck for a |
Any progress would have been on this issue! A proposal of how the API should look and / or a PR to implement this is always welcome 😄 |
Someone mentioned this issue on Gitter. https://bugs.python.org/issue15870 It seems that metaclass is not officially supported in C extensions. |
Since python 3.12 there is a function: This could be used to implement more features that In addition to the official way of doing things, I found that I was able to set the metaclass of a class by assigning to #define PY_SSIZE_T_CLEAN
#include <Python.h>
typedef struct { PyTypeObject base_type; } MyMetaclass;
static PyMethodDef MyMetaclass_methods[] = { {NULL} };
static PyObject *myclass_getitem(PyObject *self, PyObject *key) { return PyLong_FromLong(123); }
static PyMappingMethods MyMetaClassMappingMethods = {
.mp_length = NULL,
.mp_subscript = myclass_getitem,
.mp_ass_subscript = NULL,
};
static PyTypeObject MyMetaclassType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "metaclass_test.MyMetaclass",
.tp_basicsize = sizeof(MyMetaclass),
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_as_mapping = &MyMetaClassMappingMethods,
.tp_base = &PyType_Type,
.tp_methods = MyMetaclass_methods,
};
typedef struct { PyObject_HEAD } MyClass;
static PyMethodDef MyClass_methods[] = { {NULL} };
PyTypeObject *create_myclass_type(PyObject *module, PyTypeObject *metaclass) {
static PyType_Slot slots[] = {
{Py_tp_methods, MyClass_methods},
{ 0, NULL }
};
PyType_Spec spec = {
.name = "metaclass_test.MyClass",
.basicsize = sizeof(MyClass),
.itemsize = 0,
.flags = Py_TPFLAGS_DEFAULT,
.slots = slots,
};
return (PyTypeObject*)PyType_FromMetaclass(metaclass, module, &spec, NULL);
}
static PyModuleDef metaclass_test_module = {
PyModuleDef_HEAD_INIT,
.m_name = "metaclass_test",
.m_doc = "an example module",
.m_size = -1,
};
PyMODINIT_FUNC PyInit_metaclass_test(void)
{
PyObject *m = PyModule_Create(&metaclass_test_module);
PyType_Ready(&MyMetaclassType);
PyModule_AddObject(m, "MyMetaclass", (PyObject *)&MyMetaclassType);
PyTypeObject *MyClassType = create_myclass_type(m, &MyMetaclassType);
PyModule_AddObject(m, "MyClass", (PyObject*)MyClassType);
return m;
} Output: >>> from metaclass_test import MyClass, MyMetaclass
>>> type(MyClass)
<class 'metaclass_test.MyMetaclass'>
>>> MyClass['foo']
123
>>> MyMetaclass.__getitem__(MyClass, 'foo')
123 |
apparently it works by setting the
ob_type
member to a custom instance (the metaclass) of a class that derives fromtype
.The text was updated successfully, but these errors were encountered: