Документация Python неофициальный перевод

lifecycle.md

94 строк · 25.8 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.14/c-api/lifecycle.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Жизненный цикл объектов89В этом разделе объясняется, как слоты типа соотносятся друг с другом на протяжении жизни объекта. Он не является полным каноническим справочником по слотам; вместо этого обращайтесь к документации по конкретному слоту в [Структуры объектов типа](https://python-all.ru/3.14/c-api/typeobj.html#type-structs) за подробностями.1011## События жизненного цикла1213На приведённой ниже диаграмме показан порядок событий, которые могут произойти в течение жизни объекта. Стрелка от *A* к *B* означает, что событие *B* может наступить после того, как произошло событие *A*, а подпись стрелки указывает условие, которое должно выполняться, чтобы *B* наступило после *A*.1415?xml version="1.0" encoding="UTF-8" standalone="no"?1617?xml-stylesheet href="lifecycle.dot.css" type="text/css"?1819Generated by graphviz version 12.2.0 (0)2021Title: Life Events Pages: 12223События жизненного цикла start tp\_new tp\_new tp\_new start->tp\_new start-\>tp\_new вызов типа tp\_alloc tp\_alloc tp\_alloc tp\_new->tp\_alloc tp\_new-\>tp\_alloc прямой вызов tp\_init tp\_init tp\_init tp\_new->tp\_init tp\_new-\>tp\_init reachable достижимый достижимый tp\_init->reachable tp\_init-\>достижимый reachable->tp\_init достижимый-\>tp\_init tp\_traverse tp\_traverse tp\_traverse reachable->tp\_traverse достижимый-\>tp\_traverse не в циклической изоляции reachable->tp\_traverse достижимый-\>tp\_traverse периодический циклическая изоляция обнаружение finalized? финализирован? отмечен как финализирован? reachable->finalized? достижимый-\>финализирован? нет ссылок tp\_finalize tp\_finalize tp\_finalize reachable->tp\_finalize достижимый-\>tp\_finalize воскрешён (возможно удалить отметка финализации) uncollectable несобираемый несобираемый (утечка) reachable->uncollectable достижимый-\>несобираемый циклический изоляция (без GC поддержка) tp\_dealloc tp\_dealloc tp\_dealloc reachable->tp\_dealloc достижимый-\>tp\_dealloc нет ссылок tp\_traverse->finalized? tp\_traverse-\>финализирован? циклический изолят finalized?->tp\_finalize финализирован?-\>tp\_finalize нет (отметить как финализированный) tp\_clear tp\_clear tp\_clear finalized?->tp\_clear финализирован?-\>tp\_clear да tp\_finalize->tp\_clear tp\_finalize-\>tp\_clear нет ссылок или циклический изолированный tp\_finalize->tp\_dealloc tp\_finalize-\>tp\_dealloc рекомендуется вызов (см. объяснение) tp\_finalize->tp\_dealloc tp\_finalize-\>tp\_dealloc нет ссылок tp\_clear->uncollectable tp\_clear-\>неподлежащий сборке циклический изолят tp\_clear->tp\_dealloc tp\_clear-\>tp\_dealloc нет ссылок uncollectable->tp\_dealloc tp\_free tp\_free tp\_free tp\_dealloc->tp\_free tp\_dealloc-\>tp\_free прямой вызов2425Пояснение:2627- Когда новый объект создаётся вызовом его типа:2829  1. [`tp_new`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_new) вызывается для создания нового объекта.30  2. [`tp_alloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_alloc) вызывается напрямую [`tp_new`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_new) для выделения памяти под новый объект.31  3. [`tp_init`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_init) инициализирует только что созданный объект. `tp_init` может быть вызван снова для повторной инициализации объекта, если необходимо. Вызов `tp_init` также может быть полностью пропущен, например, при вызове [`__new__()`](https://python-all.ru/3.14/reference/datamodel.html#object.__new__) из кода Python.32- После завершения `tp_init` объект готов к использованию.33- Через некоторое время после удаления последней ссылки на объект:3435  1. Если объект не помечен как *финализированный*, он может быть финализирован путём пометки как *финализированный* и вызова его функции [`tp_finalize`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_finalize). Python *не* финализирует объект, когда последняя ссылка на него удаляется; используйте [`PyObject_CallFinalizerFromDealloc()`](https://python-all.ru/3.14/c-api/lifecycle.html#c.PyObject_CallFinalizerFromDealloc), чтобы гарантировать, что `tp_finalize` всегда вызывается.36  2. Если объект помечен как финализированный, [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear) может быть вызван сборщиком мусора для очистки ссылок, удерживаемых объектом. Он *не* вызывается, когда счётчик ссылок объекта достигает нуля.37  3. [`tp_dealloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_dealloc) вызывается для уничтожения объекта. Чтобы избежать дублирования кода, `tp_dealloc` обычно вызывает [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear) для освобождения ссылок объекта.38  4. Когда [`tp_dealloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_dealloc) завершает уничтожение объекта, он напрямую вызывает [`tp_free`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_free) (обычно установленный в [`PyObject_Free()`](https://python-all.ru/3.14/c-api/memory.html#c.PyObject_Free) или [`PyObject_GC_Del()`](https://python-all.ru/3.14/c-api/gcsupport.html#c.PyObject_GC_Del) автоматически в соответствии с типом) для освобождения памяти.39- Функции [`tp_finalize`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_finalize) разрешается добавить ссылку на объект, если это необходимо. Если она это делает, объект *воскрешается*, предотвращая его предстоящее уничтожение. (Только `tp_finalize` разрешено воскрешать объект; [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear) и [`tp_dealloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_dealloc) не могут без вызова `tp_finalize`.) Воскрешение объекта может привести или не привести к удалению *финализированный* пометки объекта. В настоящее время Python не удаляет *финализированный* пометку у воскрешённого объекта, если он поддерживает сборку мусора (т.е. установлен флаг [`Py_TPFLAGS_HAVE_GC`](https://python-all.ru/3.14/c-api/typeobj.html#c.Py_TPFLAGS_HAVE_GC)), но удаляет пометку, если объект не поддерживает сборку мусора; одно или оба этих поведения могут измениться в будущем.40- [`tp_dealloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_dealloc) может опционально вызывать [`tp_finalize`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_finalize) через [`PyObject_CallFinalizerFromDealloc()`](https://python-all.ru/3.14/c-api/lifecycle.html#c.PyObject_CallFinalizerFromDealloc), если желает повторно использовать этот код для помощи в уничтожении объекта. Это рекомендуется, так как гарантирует, что `tp_finalize` всегда вызывается перед уничтожением. Смотрите документацию `tp_dealloc` для примера кода.41- Если объект является членом [циклического изолята](https://python-all.ru/3.14/glossary.html#term-cyclic-isolate) и либо [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear) не удаётся разорвать цикл ссылок, либо циклический изолят не обнаружен (возможно, был вызван [`gc.disable()`](https://python-all.ru/3.14/library/gc.html#gc.disable), или флаг [`Py_TPFLAGS_HAVE_GC`](https://python-all.ru/3.14/c-api/typeobj.html#c.Py_TPFLAGS_HAVE_GC) ошибочно пропущен в одном из задействованных типов), объекты остаются навсегда несобираемыми (они «утекают»). Смотрите [`gc.garbage`](https://python-all.ru/3.14/library/gc.html#gc.garbage).4243Если объект помечен как поддерживающий сборку мусора (флаг [`Py_TPFLAGS_HAVE_GC`](https://python-all.ru/3.14/c-api/typeobj.html#c.Py_TPFLAGS_HAVE_GC) установлен в [`tp_flags`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_flags)), возможны также следующие события:4445- Сборщик мусора периодически вызывает [`tp_traverse`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_traverse) для обнаружения [циклических изолятов](https://python-all.ru/3.14/glossary.html#term-cyclic-isolate).46- Когда сборщик мусора обнаруживает [циклический изолят](https://python-all.ru/3.14/glossary.html#term-cyclic-isolate), он финализирует один из объектов в группе, помечая его как *финализированный* и вызывая его функцию [`tp_finalize`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_finalize), если она есть. Это повторяется, пока циклический изолят не перестанет существовать или все объекты не будут финализированы.47- [`tp_finalize`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_finalize) разрешается воскресить объект, добавив ссылку извне [циклического изолята](https://python-all.ru/3.14/glossary.html#term-cyclic-isolate). Новая ссылка приводит к тому, что группа объектов перестаёт образовывать циклический изолят (цикл ссылок может всё ещё существовать, но если это так, объекты больше не изолированы).48- Когда сборщик мусора обнаруживает [циклический изолят](https://python-all.ru/3.14/glossary.html#term-cyclic-isolate) и все объекты в группе уже помечены как *финализированные*, сборщик мусора очищает один или несколько неочищенных объектов в группе (возможно, параллельно), вызывая для каждого функцию [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear). Это повторяется, пока циклический изолят всё ещё существует и не все объекты были очищены.4950## Уничтожение циклического изолята5152Ниже перечислены стадии жизни гипотетического [циклического изолята](https://python-all.ru/3.14/glossary.html#term-cyclic-isolate), который продолжает существовать после финализации или очистки каждого объекта-участника. Это утечка памяти, если циклический изолят проходит через все эти стадии; он должен исчезнуть, как только все объекты будут очищены, если не раньше. Циклический изолят может исчезнуть либо из-за разрыва цикла ссылок, либо из-за того, что объекты больше не являются изолированными из-за воскрешения финализатором (см. [`tp_finalize`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_finalize)).53540. **Достижимый** (ещё не циклический изолят): Все объекты находятся в нормальном, достижимом состоянии. Цикл ссылок может существовать, но внешняя ссылка означает, что объекты ещё не изолированы.551. **Недостижимый, но непротиворечивый:** Последняя ссылка извне циклической группы объектов была удалена, в результате чего объекты стали изолированными (таким образом, рождается циклический изолят). Ни один из объектов группы ещё не был финализирован или очищен. Циклический изолят остаётся на этой стадии до следующего запуска сборщика мусора (не обязательно следующего, потому что следующий запуск может не просканировать каждый объект).562. **Смесь финализированных и нефинализированных:** Объекты в циклическом изоляте финализируются по одному, что означает, что существует период времени, когда циклический изолят состоит из смеси финализированных и нефинализированных объектов. Порядок финализации не определён, поэтому он может казаться случайным. Финализированный объект должен вести себя разумно, когда с ним взаимодействуют нефинализированные объекты, а нефинализированный объект должен уметь переносить финализацию произвольного подмножества своих референтов.573. **Все финализированы:** Все объекты в циклическом изоляте финализируются до того, как какой-либо из них будет очищен.584. **Смесь финализированных и очищенных:** Объекты могут очищаться последовательно или параллельно (но при удерживаемом [GIL](https://python-all.ru/3.14/glossary.html#term-GIL)); в любом случае некоторые закончат раньше других. Финализированный объект должен уметь переносить очистку подмножества своих референтов. [**PEP 442**](https://python-all.ru/3.14/c-api/lifecycle.html) называет эту стадию «циклическим мусором».595. **Утечка:** Если циклический изолят всё ещё существует после того, как все объекты в группе были финализированы и очищены, то объекты остаются бессрочно несобираемыми (см. [`gc.garbage`](https://python-all.ru/3.14/library/gc.html#gc.garbage)). Это ошибка, если циклический изолят достигает этой стадии – это означает, что методы [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear) участвующих объектов не смогли разорвать цикл ссылок, как требовалось.6061Если бы [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear) не существовало, у Python не было бы способа безопасно разорвать циклическую ссылку. Простое уничтожение объекта в циклической изоляции привело бы к появлению висячего указателя, вызывая неопределённое поведение, когда объект, ссылающийся на уничтоженный объект, сам уничтожается. Этап очистки превращает уничтожение объекта в двухфазовый процесс: сначала вызывается `tp_clear` для частичного уничтожения объектов, достаточного для их распутывания, а затем вызывается [`tp_dealloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_dealloc) для завершения уничтожения.6263В отличие от очистки, финализация не является фазой уничтожения. Финализированный объект всё ещё должен вести себя правильно, продолжая выполнять свои контракты на проектирование. Финализатору объекта разрешается выполнять произвольный код Python и даже разрешается предотвращать надвигающееся уничтожение путём добавления ссылки. Финализатор связан с уничтожением только порядком вызова – если он запускается, он запускается перед уничтожением, которое начинается с [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear) (если вызывается) и завершается [`tp_dealloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_dealloc).6465Шаг финализации не является обязательным для безопасного освобождения объектов в циклическом изоляте, но его существование упрощает проектирование типов, которые ведут себя разумно при очистке объектов. Очистка объекта может необходимо оставить его в сломанном, частично уничтоженном состоянии – может быть небезопасно вызывать любые методы очищенного объекта или обращаться к любым его атрибутам. С финализацией только финализированные объекты могут потенциально взаимодействовать с очищенными объектами; гарантируется, что нефинализированные объекты взаимодействуют только с неочищенными (но потенциально финализированными) объектами.6667Чтобы обобщить возможные взаимодействия:6869- Нефинализированный объект может иметь ссылки на или от нефинализированных и финализированных объектов, но не на или от очищенных объектов.70- Финализированный объект может иметь ссылки на или от нефинализированных, финализированных и очищенных объектов.71- Очищенный объект может иметь ссылки на или от финализированных и очищенных объектов, но не на или от нефинализированных объектов.7273Без каких-либо циклических ссылок объект может быть просто уничтожен, как только его последняя ссылка удалена; шаги финализации и очистки не нужны для безопасного освобождения неиспользуемых объектов. Однако может быть полезно автоматически вызывать [`tp_finalize`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_finalize) и [`tp_clear`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_clear) перед уничтожением в любом случае, потому что проектирование типов упрощается, когда все объекты всегда проходят через одну и ту же последовательность событий, независимо от того, участвовали ли они в циклическом изоляте. В настоящее время Python вызывает `tp_finalize` и `tp_clear` только по мере необходимости для уничтожения циклического изолята; это может измениться в будущей версии.7475## Функции7677Для выделения и освобождения памяти см. [Выделение объектов в куче](https://python-all.ru/3.14/c-api/allocation.html#allocating-objects).7879#### `void PyObject_CallFinalizer(PyObject *op)`8081Финализирует объект, как описано в [`tp_finalize`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_finalize). Вызывайте эту функцию (или [`PyObject_CallFinalizerFromDealloc()`](https://python-all.ru/3.14/c-api/lifecycle.html#c.PyObject_CallFinalizerFromDealloc)) вместо прямого вызова `tp_finalize`, потому что эта функция может дедуплицировать многократные вызовы `tp_finalize`. В настоящее время вызовы дедуплицируются только в том случае, если тип поддерживает сборку мусора (т.е. установлен флаг [`Py_TPFLAGS_HAVE_GC`](https://python-all.ru/3.14/c-api/typeobj.html#c.Py_TPFLAGS_HAVE_GC)); это может измениться в будущем.8283Добавлено в версии 3.4.8485#### `int PyObject_CallFinalizerFromDealloc(PyObject *op)`8687То же, что [`PyObject_CallFinalizer()`](https://python-all.ru/3.14/c-api/lifecycle.html#c.PyObject_CallFinalizer), но предназначена для вызова в начале деструктора объекта ([`tp_dealloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_dealloc)). Не должно быть никаких ссылок на объект. Если финализатор объекта воскрешает объект, эта функция возвращает -1; дальнейшее уничтожение происходить не должно. В противном случае эта функция возвращает 0, и уничтожение может продолжаться нормально.8889Добавлено в версии 3.4.9091> **См. также**92>93> [`tp_dealloc`](https://python-all.ru/3.14/c-api/typeobj.html#c.PyTypeObject.tp_dealloc) для примера кода.94