Создать тип Python из C, который реализует __dict__? - PullRequest
8 голосов
/ 21 февраля 2011
  • Как создается тип, имеющий __dict__ согласно «нормальному» классу, если бы он был определен в Python?
  • Есть ли примеры не динамических типов с * 1005?* s?
  • Могут ли типы, определенные с помощью Python, PyTypeObject проходить через type_new?

Существует tp_dictучастник PyTypeObject, но я не могу найти информацию о том, как он используется.Похоже, что в typeobject.c 1020 * что-то происходит, но я не могу расшифровать это ясно.

Вот некоторая связанная информация, которую я нашел:

Ответы [ 4 ]

6 голосов
/ 20 сентября 2012

Следующий код создаст класс, который реализует __dict__ в Python 2.x:

typedef struct {
  PyObject_HEAD
  PyObject* dict;
} BarObject;

static PyTypeObject BarObject_Type = {
  PyObject_HEAD_INIT(NULL)
};

PyMODINIT_FUNC
initFoo(void)
{
  PyObject *m;

  m = Py_InitModule("Foo", NULL);
  if (m == NULL)
    return;

  BarObject_Type.tp_new = PyType_GenericNew;
  BarObject_Type.tp_name = "Foo.Bar";
  BarObject_Type.tp_basicsize = sizeof(BarObject);
  BarObject_Type.tp_getattro = PyObject_GenericGetAttr;
  BarObject_Type.tp_setattro = PyObject_GenericSetAttr;
  BarObject_Type.tp_flags = Py_TPFLAGS_DEFAULT;
  BarObject_Type.tp_dictoffset = offsetof(BarObject,dict);
  BarObject_Type.tp_doc = "Doc string for class Bar in module Foo.";
  if (PyType_Ready(&BarObject_Type) < 0)
    return;

  Py_INCREF(&BarObject_Type);
  PyModule_AddObject(m, "Bar", (PyObject*)&BarObject_Type);
}

Важным битом является член tp_dictoffset структуры PyTypeObject (http://docs.python.org/c-api/typeobj.html):

Если экземпляры этого типа имеют словарь, содержащий переменные экземпляра, это поле ненулевое и содержит смещение в экземплярах типа словаря переменных экземпляра, это смещение используется PyObject_GenericGetAttr().

Не путайте это поле с tp_dict, то есть словарем для атрибутов самого объекта типа.

2 голосов
/ 21 февраля 2011

Чтобы ответить на последний вопрос первым: Нет, type_new используется только для «типов кучи», которые динамически определяются во время выполнения (например, с помощью оператора класса). Статически определенные типы инициализируются с использованием PyType_Ready().

Чтобы ответить на ваш первый вопрос: чтобы создать тип расширения с дескриптором __dict__, вам нужно динамически распределить тип так же, как это делает интерпретатор для определения класса.

Один из способов получить примеры для этого - сделать так, как предлагает Джон, и сгенерировать несколько собственных примеров с помощью Cython.

Для CPython 2.x вы можете посмотреть на метод build_class в исходном коде CPython (http://svn.python.org/view/python/trunk/Python/ceval.c?view=markup), чтобы получить представление о шагах, связанных с полностью общим решением.

Если вы используете Python 3, то этот вопрос может представлять интерес: Что делает встроенная в Python __build_class__?

То есть, как конкретное решение CPython 3.x, самое простое, что нужно сделать, это вызвать builtins.__build_class__ с соответствующими аргументами через C API.

1 голос
/ 21 февраля 2011

Я этого не делал, мне неловко плохо использовать C-API, но, согласно документам, этого должно быть достаточно при использовании PyObject_GenericGetAttr и PyObject_GenericSetAttr для методов getattro и setattro , Вам также необходимо иметь атрибут PyObject, который называется __dict__.

Вы пробовали это?

0 голосов
/ 21 февраля 2011

Как насчет написания некоторого кода Python, определяющего класс и метод или два, компилирующих его с помощью Cython и проверяющих сгенерированный код C?

...