Я хотел бы понять внутренности системы импорта Python, включая грубые пятна. В API Python C documentation, есть эта немногословная ссылка на один такое грубое место:Статическая инициализация с указателем на переменную extern
Это настолько важно, что мы собираемся взять верх его обособленно еще дальше:
PyObject_HEAD_INIT(NULL)
Эта линия немного бородавка; что мы хотели бы написать это:
PyObject_HEAD_INIT(&PyType_Type)
как тип объекта типа является «типа», но это не является строго в соответствии C и некоторые компилятор жалуются.
Почему это не строго соответствует C? Почему некоторые компиляторы принимают это без жалобы, а другие нет?
теперь я думаю, что следующий может ввести в заблуждение, переходите к «СОДЕРЖАТЕЛЬНОЙ EDIT»
Прокрутка о странице вниз есть то, что я считаю, является ключом. Эта цитата относится к инициализации другого члена структуры, но это похоже на ту же проблему, и на этот раз это объясняется.
Мы хотели бы просто присвоить это к tp_new слот, но мы не можем, ради портативность, на некоторых платформах или компиляторов, мы не можем статически инициализировать элемент структуры с функцией, определенной в другом C
Это все еще оставляет меня в замешательстве, отчасти из-за выбора слова «модуль». Я думаю, что вторая цитата означала, что статическая инициализация, основанная на вызовах функций в отдельных единицах компиляции, является нестандартным расширением. Я до сих пор не понимаю, почему это так. Это то, что происходит в первой цитате?
СУЩЕСТВЕННОМУ EDIT:
Использование PyObject_HEAD_INIT(NULL)
рекомендуется идти на самом верху инициализации экземпляра PyTypeObject
.
Определение PyTypeObject выглядит следующим образом:
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
/*... lots more ... */
} PyTypeObject;
PyObject_HEAD_INIT(NULL)
макрос используется для инициализации вершины экземпляров PyTypeObject. Верхняя часть определения PyTypeObject
создается макросом PyObject_VAR_HEAD
. PyObject_VAR_HEAD
является:
/* PyObject_VAR_HEAD defines the initial segment of all variable-size
* container objects. These end with a declaration of an array with 1
* element, but enough space is malloc'ed so that the array actually
* has room for ob_size elements. Note that ob_size is an element count,
* not necessarily a byte count.
*/
#define PyObject_VAR_HEAD \
PyObject_HEAD \
Py_ssize_t ob_size; /* Number of items in variable part */
#define Py_INVALID_SIZE (Py_ssize_t)-1
В свою очередь, PyObject_HEAD
расширяется:
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD \
_PyObject_HEAD_EXTRA \
Py_ssize_t ob_refcnt; \
struct _typeobject *ob_type;
_PyObject_HEAD_EXTRA
используется только при отладке сборок и обычно расширяется до нуля. Элементами, инициализированными макросом PyObject_HEAD_INIT, являются ob_refcnt и ob_type.ob_type - это тот, который мы хотели бы инициализировать с помощью &PyType_Type
, но нам сказали, что это нарушит стандарт C. ob_type указывает на _typeobject, который typedef'd является PyTypeObject (той же структурой, которую мы пытаемся инициализировать). Мы используем PyObject_HEAD_INIT макрос, который инициализирует эти два значения, расширяется так:
#define PyObject_HEAD_INIT(type) \
_PyObject_EXTRA_INIT \
1, type,
Итак, мы начинаем подсчет ссылок на 1 и установив указатель члена на то, что в параметре типа. Документация Python говорит, что мы не можем установить параметр типа it по адресу PyType_Type, потому что это не строго стандарт C, поэтому мы соглашаемся на NULL.
PyType_Type
указано в одной и той же части перевода несколькими строками ниже.
PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */
PyAPI_DATA
определен в другом месте. Он имеет несколько условных определений.
#define PyAPI_DATA(RTYPE) extern __declspec(dllexport) RTYPE
#define PyAPI_DATA(RTYPE) extern RTYPE
Так документация API Python говорит, что мы хотели бы, чтобы инициализировать экземпляр PyTypeObject с указателем на ранее объявленной PyTypeObject, который был объявлен с экстерном классификатором. Что в С-стандарте нарушило бы?
Инициализация PyType_Type происходит в .c файле. Типичное расширение Python, который инициализирует PyTypeObject, как описано выше, будет динамически загружен код, который был составлен с этой инициализации:
PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
(destructor)type_dealloc, /* tp_dealloc */
/* ... lots more ... */
}
Каково определение PyObject_VAR_HEAD, для которого PyObject_HEAD_INIT (...) является инициализатором? –
Я думаю, что это отклоняется от курса, но определение: #define PyObject_VAR_HEAD \ PyObject_HEAD \ Py_ssize_t ob_size; Я могу туннелировать через макросы и добавить к ней через несколько минут. – Praxeolitic
«Я думаю, что это отклоняется от курса». Ну, тогда вам не хватает базового понимания. Что вам нужно знать здесь, это тип того, что инициализирует '& PyType_Type' (или NULL). Итак, вы должны опубликовать определение PyObject_HEAD.И если это определено в терминах еще одного макроса, опубликуйте его определение и так далее. Если вы действительно не хотите никакой помощи. –