Я пытаюсь определить функцию, которая создала бы класс Python с использованием C API, который происходит от произвольного Python типа base
и имеет дополнительное поле void* my_ptr
в своем необработанном C -подобное расположение объектов. Я хочу, чтобы он повторно использовал Python __dict__
функциональность.
Я не делаю это в C, поэтому не имею доступа к C макросам. Моя первоначальная попытка выглядит следующим образом (псевдокод):
PyType Derive(PyType base) {
var newType = new PyType(...);
newType.tp_flags = HeapType | BaseType; // <- this is important,
// one should be able to add new attributes and otherwise use __dict__, subclass, etc
... filling in other things ...
int my_ptr_offset = base.tp_basesize; // put my_ptr immediately after base type data
newType.tp_basesize = my_ptr_offset + sizeof(void*); // instances of new type
// will have instance size = base size + size of my_ptr
...
return newType;
}
Проблема в том, что этот код ломается, когда base
равен builtins.object
. В этом случае tp_basesize
не считает поле, в котором обычно хранится __dict__
, а my_ptr_offset
в конечном итоге указывает на это поле, что в конечном итоге приводит к его перезаписи пользователем my_ptr
.
* 1016. * Любой простой Python класс, производный от
object
, не имеет этой проблемы. Например:
class MySimpleClass: pass
На 64-битной машине:
PyType mySimpleClass = ...;
PyType object = ...;
mySimpleClass.tp_basesize // <- 32, includes __dict__
object.tp_basesize // <- 16, does not include space for __dict__
Я также заметил похожую проблему с builtins.exception
.
Сейчас я просто вручную проверяю exception
и object
и добавьте 2x sizeof(void*)
к tp_basesize
, что, кажется, работает. Но я хотел бы понять, как правильно обрабатывать этот макет.