-
Notifications
You must be signed in to change notification settings - Fork 783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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: