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

pickle.md

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

1> **Источник:** https://python-all.ru/2.7/library/pickle.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 11.1. [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) – сериализация объектов Python89Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) реализует фундаментальный, но мощный алгоритм для сериализации и десериализации структуры объектов Python. «Пиклирование» – это процесс, при котором иерархия объектов Python преобразуется в поток байтов, а «распиклирование» – обратная операция, при которой поток байтов преобразуется обратно в иерархию объектов. Пиклирование (и распиклирование) также известно как «сериализация», «маршалинг», [1](https://python-all.ru/2.7/library/pickle.html#id11) или «уплощение», однако, чтобы избежать путаницы, здесь используются термины «пиклирование» и «распиклирование».1011Эта документация описывает как модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle), так и модуль [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle).1213> **Предупреждение**14>15> Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) не защищён от ошибочных или вредоносных данных. Никогда не десериализуйте данные, полученные из ненадёжного или непроверенного источника.1617## 11.1.1. Взаимосвязь с другими модулями Python1819У модуля [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) есть оптимизированный собрат, называемый модулем [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle). Как следует из названия, [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) написан на C, поэтому он может быть до 1000 раз быстрее, чем [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle). Однако он не поддерживает наследование от классов [`Pickler()`](https://python-all.ru/2.7/library/pickle.html#pickle.Pickler) и [`Unpickler()`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler), потому что в [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) это функции, а не классы. Большинству приложений эта функциональность не нужна, и они могут выиграть от повышенной производительности [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle). В остальном интерфейсы двух модулей почти идентичны; общий интерфейс описан в этом руководстве, а различия отмечены там, где это необходимо. В дальнейшем мы используем термин «pickle» для совместного описания модулей [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) и [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle).2021Потоки данных, производимые двумя модулями, гарантированно взаимозаменяемы.2223В Python есть более примитивный модуль сериализации [`marshal`](https://python-all.ru/2.7/library/marshal.html#module-marshal), но в целом [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) всегда должен быть предпочтительным способом сериализации объектов Python. [`marshal`](https://python-all.ru/2.7/library/marshal.html#module-marshal) существует в первую очередь для поддержки файлов `.pyc` в Python.2425Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) отличается от [`marshal`](https://python-all.ru/2.7/library/marshal.html#module-marshal) несколькими важными особенностями:2627- Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) отслеживает уже сериализованные объекты, чтобы последующие ссылки на тот же объект не сериализовались повторно. [`marshal`](https://python-all.ru/2.7/library/marshal.html#module-marshal) этого не делает.2829  This has implications both for recursive objects and object sharing. Recursive objects are objects that contain references to themselves. These are not handled by marshal, and in fact, attempting to marshal recursive objects will crash your Python interpreter. Object sharing happens when there are multiple references to the same object in different places in the object hierarchy being serialized. [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) stores such objects only once, and ensures that all other references point to the master copy. Shared objects remain shared, which can be very important for mutable objects.30- [`marshal`](https://python-all.ru/2.7/library/marshal.html#module-marshal) нельзя использовать для сериализации пользовательских классов и их экземпляров. [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) может прозрачно сохранять и восстанавливать экземпляры классов, однако определение класса должно быть импортируемо и находиться в том же модуле, что и при сохранении объекта.31- Формат сериализации [`marshal`](https://python-all.ru/2.7/library/marshal.html#module-marshal) не гарантирует переносимости между версиями Python. Поскольку его основная задача – поддержка файлов `.pyc`, разработчики Python оставляют за собой право изменять формат сериализации несовместимым с предыдущими версиями образом, если возникнет необходимость. Формат сериализации [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) гарантирует обратную совместимость между выпусками Python.3233Обратите внимание, что сериализация – это более примитивное понятие, чем персистентность; хотя [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) читает и записывает файловые объекты, он не решает проблему именования персистентных объектов, ни (ещё более сложную) проблему конкурентного доступа к персистентным объектам. Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) может преобразовать сложный объект в поток байтов и может преобразовать поток байтов обратно в объект с той же внутренней структурой. Вероятно, самое очевидное, что можно сделать с этими потоками байтов – записать их в файл, но также можно отправить их по сети или сохранить в базе данных. Модуль [`shelve`](https://python-all.ru/2.7/library/shelve.html#module-shelve) предоставляет простой интерфейс для пиклирования и распиклирования объектов в файлах баз данных в стиле DBM.3435## 11.1.2. Формат потока данных3637Формат данных, используемый [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle), является специфичным для Python. Это даёт преимущество: нет ограничений, налагаемых внешними стандартами, такими как XDR (который не может представлять разделение указателей); однако это означает, что программы не на Python могут не иметь возможности восстановить пиклированные объекты Python.3839По умолчанию формат данных [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) использует печатное ASCII-представление. Это немного объёмнее, чем двоичное представление. Большим преимуществом использования печатного ASCII (и некоторых других характеристик представления [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle)) является то, что для целей отладки или восстановления человек может прочитать пиклированный файл с помощью стандартного текстового редактора.4041В настоящее время существует 3 различных протокола, которые можно использовать для пиклирования.4243- Версия протокола 0 является оригинальным ASCII-протоколом и обратно совместима с предыдущими версиями Python.44- Версия протокола 1 – это старый двоичный формат, также совместимый с ранними версиями Python.45- Версия протокола 2 была представлена в Python 2.3. Она обеспечивает гораздо более эффективную упаковку (pickling) [классов нового стиля](https://python-all.ru/2.7/glossary.html#term-new-style-class).4647Смотрите [**PEP 307**](https://python-all.ru/2.7/library/pickle.html) для получения дополнительной информации.4849Если *протокол* не указан, используется протокол 0. Если *протокол* указан как отрицательное значение или [`HIGHEST_PROTOCOL`](https://python-all.ru/2.7/library/pickle.html#pickle.HIGHEST_PROTOCOL), будет использована самая высокая доступная версия протокола.5051Изменено в версии 2.3: Добавлен параметр *протокол*.5253Двоичный формат, который немного эффективнее, можно выбрать, указав *протокол* версии \>= 1.5455## 11.1.3. Использование5657Чтобы сериализовать иерархию объектов, сначала создаётся pickler, затем вызывается его метод [`dump()`](https://python-all.ru/2.7/library/pickle.html#pickle.dump). Чтобы десериализовать поток данных, сначала создаётся unpickler, затем вызывается его метод [`load()`](https://python-all.ru/2.7/library/pickle.html#pickle.load). Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) предоставляет следующую константу:5859#### `pickle.HIGHEST_PROTOCOL`6061Самая высокая доступная версия протокола. Это значение можно передать как аргумент *protocol*.6263Новое в версии 2.3.6465> **Примечание**66>67> Файлы pickle, созданные с протоколами \>= 1, следует всегда открывать в бинарном режиме. Для старого ASCII-протокола pickle 0 можно использовать как текстовый, так и бинарный режим, при условии соблюдения согласованности.68>69> Файл pickle, записанный с протоколом 0 в бинарном режиме, будет содержать одиночные символы перевода строки в качестве разделителей строк и поэтому будет выглядеть «странно» при просмотре в Блокноте или других редакторах, не поддерживающих этот формат.7071Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) предоставляет следующие функции для упрощения процесса упаковки:7273#### `pickle.dump(obj, file[, protocol])`7475Записывает пиклированное представление объекта *obj* в открытый файловый объект *file*. Это эквивалентно `Pickler(file, protocol).dump(obj)`.7677Если параметр *протокол* опущен, используется протокол 0. Если *протокол* указан как отрицательное значение или [`HIGHEST_PROTOCOL`](https://python-all.ru/2.7/library/pickle.html#pickle.HIGHEST_PROTOCOL), будет использована самая высокая версия протокола.7879Изменено в версии 2.3: Добавлен параметр *протокол*.8081*file* должен иметь метод `write()`, который принимает один строковый аргумент. Таким образом, это может быть файловый объект, открытый для записи, объект [`StringIO`](https://python-all.ru/2.7/library/stringio.html#module-StringIO) или любой другой пользовательский объект, соответствующий этому интерфейсу.8283#### `pickle.load(file)`8485Читает строку из открытого файлового объекта *file* и интерпретирует её как поток данных pickle, восстанавливая и возвращая исходную иерархию объектов. Это эквивалентно `Unpickler(file).load()`.8687*file* должен иметь два метода: метод `read()`, принимающий целочисленный аргумент, и метод [`readline()`](https://python-all.ru/2.7/library/readline.html#module-readline), не требующий аргументов. Оба метода должны возвращать строку. Таким образом, *file* может быть файловым объектом, открытым для чтения, объектом [`StringIO`](https://python-all.ru/2.7/library/stringio.html#module-StringIO) или любым другим пользовательским объектом, соответствующим этому интерфейсу.8889Эта функция автоматически определяет, был ли поток данных записан в двоичном режиме или нет.9091#### `pickle.dumps(obj[, protocol])`9293Возвращает пиклированное представление объекта в виде строки, вместо записи в файл.9495Если параметр *протокол* опущен, используется протокол 0. Если *протокол* указан как отрицательное значение или [`HIGHEST_PROTOCOL`](https://python-all.ru/2.7/library/pickle.html#pickle.HIGHEST_PROTOCOL), будет использована самая высокая версия протокола.9697Изменено в версии 2.3: Был добавлен параметр *протокол*.9899#### `pickle.loads(string)`100101Читает иерархию пиклированных объектов из строки. Символы в строке после представления пиклированного объекта игнорируются.102103Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) также определяет три исключения:104105#### `exception pickle.PickleError`106107Общий базовый класс для других исключений, определённых ниже. Наследует от [`Exception`](https://python-all.ru/2.7/library/exceptions.html#exceptions.Exception).108109#### `exception pickle.PicklingError`110111Это исключение возбуждается, когда непиклируемый объект передаётся методу [`dump()`](https://python-all.ru/2.7/library/pickle.html#pickle.dump).112113#### `exception pickle.UnpicklingError`114115Это исключение возбуждается при возникновении проблемы распиклирования объекта. Обратите внимание, что во время распиклирования могут также возбуждаться другие исключения, включая (но не ограничиваясь) [`AttributeError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.AttributeError), [`EOFError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.EOFError), [`ImportError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ImportError) и [`IndexError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.IndexError).116117Модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) также экспортирует два вызываемых объекта: [2](https://python-all.ru/2.7/library/pickle.html#id12), [`Pickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Pickler) и [`Unpickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler).118119#### `class pickle.Pickler(file[, protocol])`120121Принимает файлоподобный объект, в который будет записан поток данных pickle.122123Если параметр *protocol* опущен, используется протокол 0. Если *protocol* задан как отрицательное значение или [`HIGHEST_PROTOCOL`](https://python-all.ru/2.7/library/pickle.html#pickle.HIGHEST_PROTOCOL), будет использована самая высокая версия протокола.124125Изменено в версии 2.3: Введён параметр *protocol*.126127*file* должен иметь метод `write()`, принимающий один строковый аргумент. Таким образом, это может быть открытый файловый объект, объект [`StringIO`](https://python-all.ru/2.7/library/stringio.html#module-StringIO) или любой другой пользовательский объект, соответствующий этому интерфейсу.128129Объекты [`Pickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Pickler) определяют один (или два) открытых метода:130131#### `dump(obj)`132133Записывает представление *объекта* в pickle в открытый файловый объект, переданный конструктору. Будет использован бинарный или ASCII-формат в зависимости от значения аргумента *protocol*, переданного конструктору.134135#### `clear_memo()`136137Очищает «memo» (память) пиклера. Memo – это структура данных, которая запоминает, какие объекты пиклер уже видел, чтобы общие или рекурсивные объекты сериализовались по ссылке, а не по значению. Этот метод полезен при повторном использовании пиклеров.138139> **Примечание**140>141> До Python 2.3 [`clear_memo()`](https://python-all.ru/2.7/library/pickle.html#pickle.Pickler.clear_memo) был доступен только для пиклеров, созданных [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle). В модуле [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) у пиклеров есть переменная экземпляра `memo`, представляющая собой словарь Python. Таким образом, чтобы очистить память для пиклера модуля [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle), можно было сделать следующее:142>143> ```python144> mypickler.memo.clear()145> ```146>147> Код, которому не требуется поддержка старых версий Python, должен просто использовать [`clear_memo()`](https://python-all.ru/2.7/library/pickle.html#pickle.Pickler.clear_memo).148149Можно выполнить несколько вызовов метода [`dump()`](https://python-all.ru/2.7/library/pickle.html#pickle.dump) одного и того же экземпляра [`Pickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Pickler). Эти вызовы должны затем быть сопоставлены с таким же количеством вызовов метода [`load()`](https://python-all.ru/2.7/library/pickle.html#pickle.load) соответствующего экземпляра [`Unpickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler). Если один и тот же объект сериализуется несколькими вызовами [`dump()`](https://python-all.ru/2.7/library/pickle.html#pickle.dump), все [`load()`](https://python-all.ru/2.7/library/pickle.html#pickle.load) будут давать ссылки на один и тот же объект. [3](https://python-all.ru/2.7/library/pickle.html#id13)150151Объекты [`Unpickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler) определяются как:152153#### `class pickle.Unpickler(file)`154155Принимает файлоподобный объект, из которого будет читать поток данных pickle. Этот класс автоматически определяет, был ли поток данных записан в бинарном режиме или нет, поэтому ему не нужен флаг, как в фабрике [`Pickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Pickler).156157*file* должен иметь два метода: метод `read()`, принимающий целочисленный аргумент, и метод [`readline()`](https://python-all.ru/2.7/library/readline.html#module-readline), не требующий аргументов. Оба метода должны возвращать строку. Таким образом, *file* может быть файловым объектом, открытым для чтения, объектом [`StringIO`](https://python-all.ru/2.7/library/stringio.html#module-StringIO) или любым другим пользовательским объектом, соответствующим этому интерфейсу.158159Объекты [`Unpickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler) имеют один (или два) открытых метода:160161#### `load()`162163Читает представление объекта в pickle из открытого файлового объекта, переданного конструктору, и возвращает восстановленную иерархию объектов, указанную в нём.164165Этот метод автоматически определяет, был ли поток данных записан в бинарном режиме или нет.166167#### `noload()`168169Этот метод похож на [`load()`](https://python-all.ru/2.7/library/pickle.html#pickle.load), за исключением того, что он не создаёт реально никаких объектов. Это полезно в первую очередь для поиска так называемых «persistent ids» (постоянных идентификаторов), которые могут быть использованы в потоке данных pickle. См. раздел [Протокол pickle](https://python-all.ru/2.7/library/pickle.html#pickle-protocol) ниже для получения дополнительных сведений.170171**Примечание:** метод [`noload()`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler.noload) в настоящее время доступен только для объектов [`Unpickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler), созданных с помощью модуля [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle). Объекты [`Unpickler`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler) модуля [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) не имеют метода [`noload()`](https://python-all.ru/2.7/library/pickle.html#pickle.Unpickler.noload).172173## 11.1.4. Что можно упаковать и распаковать с помощью pickle?174175Следующие типы можно сериализовать:176177- `None`, `True` и `False`178- целые числа, длинные целые числа, числа с плавающей запятой, комплексные числа179- обычные и Unicode-строки180- кортежи, списки, множества и словари, содержащие только сериализуемые объекты181- Функции, определённые на верхнем уровне модуля.182- встроенные функции, определённые на верхнем уровне модуля183- классы, определённые на верхнем уровне модуля184- экземпляры таких классов, у которых [`__dict__`](https://python-all.ru/2.7/library/stdtypes.html#object.__dict__) или результат вызова [`__getstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__getstate__) является сериализуемым (подробнее см. раздел [Протокол pickle](https://python-all.ru/2.7/library/pickle.html#pickle-protocol)).185186Попытки сериализовать несериализуемые объекты вызовут исключение [`PicklingError`](https://python-all.ru/2.7/library/pickle.html#pickle.PicklingError); когда это происходит, некоторое количество байт может быть уже записано в базовый файл. Попытка сериализовать сильно рекурсивную структуру данных может превысить максимальную глубину рекурсии, в этом случае будет возбуждено исключение [`RuntimeError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.RuntimeError). Можно аккуратно увеличить этот предел с помощью [`sys.setrecursionlimit()`](https://python-all.ru/2.7/library/sys.html#sys.setrecursionlimit).187188Обратите внимание, что функции (встроенные и определённые пользователем) упаковываются по «полностью квалифицированному» имени, а не по значению. Это означает, что упаковывается только имя функции вместе с именем модуля, в котором функция определена. Ни код функции, ни какие-либо её атрибуты не упаковываются. Поэтому определяющий модуль должен быть импортируемым в среде распаковки, и модуль должен содержать именованный объект, иначе будет возбуждено исключение. [4](https://python-all.ru/2.7/library/pickle.html#id14)189190Аналогично, классы сериализуются по именованной ссылке, поэтому в среде десериализации действуют те же ограничения. Обратите внимание, что ни код класса, ни его данные не сериализуются, поэтому в следующем примере атрибут класса `attr` не восстанавливается в среде десериализации:191192```python193class Foo:194    attr = 'a class attr'195196picklestring = pickle.dumps(Foo)197```198199Эти ограничения объясняют, почему сериализуемые функции и классы должны быть определены на верхнем уровне модуля.200201Аналогично, при сериализации экземпляров классов код и данные самого класса не сериализуются вместе с ними. Сериализуются только данные экземпляра. Это сделано намеренно, чтобы можно было исправить ошибки в классе или добавить в него методы и по-прежнему загружать объекты, созданные с помощью более старой версии класса. Если планируется использовать долгоживущие объекты, которые переживут множество версий класса, будет разумно добавить в объекты номер версии, чтобы можно было выполнять соответствующие преобразования с помощью метода [`__setstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__setstate__) класса.202203## 11.1.5. Протокол pickle204205В этом разделе описывается «протокол pickle», который определяет интерфейс между пиклером/анпиклером и сериализуемыми объектами. Этот протокол предоставляет стандартный способ определения, настройки и управления тем, как объекты сериализуются и десериализуются. Описание в этом разделе не охватывает специальные настройки, которые можно применить для обеспечения большей безопасности среды распаковки от недоверенных потоков данных pickle; см. раздел [Создание подклассов Unpickler](https://python-all.ru/2.7/library/pickle.html#pickle-sub) для получения более подробной информации.206207### 11.1.5.1. Упаковка и распаковка обычных экземпляров классов208209#### `object.__getinitargs__()`210211Когда сериализованный экземпляр класса распаковывается, его метод [`__init__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__init__) обычно *не* вызывается. Если необходимо, чтобы метод [`__init__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__init__) вызывался при распаковке, класс старого стиля может определить метод [`__getinitargs__()`](https://python-all.ru/2.7/library/pickle.html#object.__getinitargs__), который должен возвращать *кортеж* позиционных аргументов, передаваемых конструктору класса (например, [`__init__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__init__)). Именованные аргументы не поддерживаются. Метод [`__getinitargs__()`](https://python-all.ru/2.7/library/pickle.html#object.__getinitargs__) вызывается во время упаковки; возвращаемый кортеж включается в pickle для экземпляра.212213#### `object.__getnewargs__()`214215Типы нового стиля могут предоставлять метод [`__getnewargs__()`](https://python-all.ru/2.7/library/pickle.html#object.__getnewargs__), который используется для протокола 2. Реализация этого метода необходима, если тип устанавливает некоторые внутренние инварианты при создании экземпляра, или если выделение памяти зависит от значений, передаваемых методу [`__new__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__new__) для этого типа (как для кортежей и строк). Экземпляры [класса нового стиля](https://python-all.ru/2.7/glossary.html#term-new-style-class) `C` создаются с помощью216217```python218obj = C.__new__(C, *args)219```220221где *аргументы* – это результат вызова [`__getnewargs__()`](https://python-all.ru/2.7/library/pickle.html#object.__getnewargs__) для исходного объекта; если [`__getnewargs__()`](https://python-all.ru/2.7/library/pickle.html#object.__getnewargs__) отсутствует, предполагается пустой кортеж.222223#### `object.__getstate__()`224225Классы могут дополнительно влиять на то, как упаковываются их экземпляры; если класс определяет метод [`__getstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__getstate__), он вызывается и возвращаемое состояние упаковывается как содержимое экземпляра, а не содержимое его словаря. Если метод [`__getstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__getstate__) отсутствует, упаковывается [`__dict__`](https://python-all.ru/2.7/library/stdtypes.html#object.__dict__) экземпляра.226227#### `object.__setstate__(state)`228229При распаковке, если класс также определяет метод [`__setstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__setstate__), он вызывается с распакованным состоянием. [5](https://python-all.ru/2.7/library/pickle.html#id15) Если метода [`__setstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__setstate__) нет, упакованное состояние должно быть словарём, и его элементы присваиваются словарю нового экземпляра. Если класс определяет оба метода [`__getstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__getstate__) и [`__setstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__setstate__), объект состояния не обязан быть словарём, и эти методы могут делать что угодно. [6](https://python-all.ru/2.7/library/pickle.html#id16)230231> **Примечание**232>233> Для [классов нового стиля](https://python-all.ru/2.7/glossary.html#term-new-style-class), если [`__getstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__getstate__) возвращает ложное значение, метод [`__setstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__setstate__) не будет вызван.234235> **Примечание**236>237> При распаковке для экземпляра могут вызываться некоторые методы, такие как [`__getattr__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__getattr__), [`__getattribute__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__getattribute__) или [`__setattr__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__setattr__). Если эти методы зависят от выполнения некоторого внутреннего инварианта, тип должен реализовать либо [`__getinitargs__()`](https://python-all.ru/2.7/library/pickle.html#object.__getinitargs__), либо [`__getnewargs__()`](https://python-all.ru/2.7/library/pickle.html#object.__getnewargs__), чтобы установить такой инвариант; в противном случае не будут вызваны ни [`__new__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__new__), ни [`__init__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__init__).238239### 11.1.5.2. Упаковка и распаковка типов расширений240241#### `object.__reduce__()`242243Когда `Pickler` встречает объект типа, о котором ничего не знает (например, тип расширения), он ищет в двух местах подсказку, как его упаковать. Один вариант – чтобы объект реализовал метод [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__). Если он предоставлен, при упаковке [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__) будет вызван без аргументов и должен вернуть либо строку, либо кортеж.244245Если возвращается строка, она задаёт имя глобальной переменной, содержимое которой упаковывается обычным образом. Строка, возвращаемая [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__), должна быть локальным именем объекта относительно его модуля; модуль pickle ищет пространство имён модуля, чтобы определить модуль объекта.246247Если возвращается кортеж, он должен содержать от двух до пяти элементов. Необязательные элементы можно опустить или передать `None` в качестве их значения. Содержимое этого кортежа упаковывается как обычно и используется для восстановления объекта при распаковке. Семантика каждого элемента:248249- Вызываемый объект, который будет вызван для создания начальной версии объекта. Следующий элемент кортежа предоставит аргументы для этого вызываемого объекта, а последующие элементы – дополнительную информацию о состоянии, которая затем будет использована для полного восстановления упакованных данных.250251  В среде распаковки этот объект должен быть классом, вызываемым объектом, зарегистрированным как «безопасный конструктор» (см. ниже), или иметь атрибут `__safe_for_unpickling__` с истинным значением. В противном случае в среде распаковки будет возбуждено `UnpicklingError`. Обратите внимание, что, как обычно, вызываемый объект упаковывается по имени.252- Кортеж аргументов для вызываемого объекта.253254  Изменено в версии 2.5: Ранее этот аргумент мог также быть `None`.255- Необязательно, состояние объекта, которое будет передано методу [`__setstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__setstate__) объекта, как описано в разделе [Упаковка и распаковка обычных экземпляров классов](https://python-all.ru/2.7/library/pickle.html#pickle-inst). Если у объекта нет метода [`__setstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__setstate__), то, как и выше, значение должно быть словарём, и оно будет добавлено в [`__dict__`](https://python-all.ru/2.7/library/stdtypes.html#object.__dict__) объекта.256- Необязательно, итератор (не последовательность), выдающий последовательные элементы списка. Эти элементы списка будут упакованы и добавлены к объекту с помощью `obj.append(item)` или `obj.extend(list_of_items)`. Это в основном используется для подклассов списка, но может использоваться и другими классами, если они имеют методы `append()` и `extend()` с соответствующей сигнатурой. (Используется ли `append()` или `extend()`, зависит от используемой версии протокола pickle, а также от количества добавляемых элементов, поэтому должны поддерживаться оба.)257- Необязательно, итератор (не последовательность), выдающий последовательные элементы словаря, которые должны быть кортежами вида `(key, value)`. Эти элементы будут упакованы и сохранены в объект с помощью `obj[key] = value`. Это в основном используется для подклассов словаря, но может использоваться и другими классами, если они реализуют [`__setitem__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__setitem__).258259#### `object.__reduce_ex__(protocol)`260261Иногда полезно знать версию протокола при реализации [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__). Это можно сделать, реализовав метод с именем [`__reduce_ex__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce_ex__) вместо [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__). [`__reduce_ex__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce_ex__), если он существует, вызывается в предпочтение [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__) (вы всё ещё можете предоставить [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__) для обратной совместимости). Метод [`__reduce_ex__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce_ex__) будет вызван с одним целочисленным аргументом – версией протокола.262263Класс [`object`](https://python-all.ru/2.7/library/functions.html#object) реализует как [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__), так и [`__reduce_ex__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce_ex__); однако, если подкласс переопределяет [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__), но не [`__reduce_ex__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce_ex__), реализация [`__reduce_ex__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce_ex__) обнаруживает это и вызывает [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__).264265Альтернатива реализации метода [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__) на упаковываемом объекте – зарегистрировать вызываемый объект в модуле [`copy_reg`](https://python-all.ru/2.7/library/copy_reg.html#module-copy_reg). Этот модуль предоставляет способ регистрации «функций сокращения» (reduction functions) и конструкторов для пользовательских типов. Функции сокращения имеют ту же семантику и интерфейс, что и метод [`__reduce__()`](https://python-all.ru/2.7/library/pickle.html#object.__reduce__), описанный выше, за исключением того, что они вызываются с одним аргументом – упаковываемым объектом.266267Зарегистрированный конструктор считается «безопасным конструктором» для целей распаковки, как описано выше.268269### 11.1.5.3. Упаковка и распаковка внешних объектов270271В интересах сохранения объектов (object persistence) модуль [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) поддерживает понятие ссылки на объект вне потока упакованных данных. Такие объекты обозначаются «постоянным идентификатором» (persistent id), который представляет собой произвольную строку из печатных ASCII-символов. Разрешение таких имён не определяется модулем [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle); он делегирует это разрешение пользовательским функциям упаковщика и распаковщика. [7](https://python-all.ru/2.7/library/pickle.html#id17)272273Чтобы определить разрешение внешних постоянных идентификаторов, необходимо установить атрибут `persistent_id` объекта pickler и атрибут `persistent_load` объекта unpickler.274275Чтобы упаковать объекты, имеющие внешний постоянный идентификатор, упаковщик должен иметь пользовательский метод `persistent_id()`, который принимает объект в качестве аргумента и возвращает либо `None`, либо постоянный идентификатор для этого объекта. Когда возвращается `None`, упаковщик просто упаковывает объект как обычно. Когда возвращается строка постоянного идентификатора, упаковщик упаковывает эту строку вместе с маркером, чтобы распаковщик распознал строку как постоянный идентификатор.276277Чтобы распаковать внешние объекты, распаковщик должен иметь пользовательскую функцию `persistent_load()`, которая принимает строку постоянного идентификатора и возвращает ссылочный объект.278279Вот глупый пример, который *возможно* прояснит ситуацию:280281```python282import pickle283from cStringIO import StringIO284285src = StringIO()286p = pickle.Pickler(src)287288def persistent_id(obj):289    if hasattr(obj, 'x'):290        return 'the value %d' % obj.x291    else:292        return None293294p.persistent_id = persistent_id295296class Integer:297    def __init__(self, x):298        self.x = x299    def __str__(self):300        return 'My name is integer %d' % self.x301302i = Integer(7)303print i304p.dump(i)305306datastream = src.getvalue()307print repr(datastream)308dst = StringIO(datastream)309310up = pickle.Unpickler(dst)311312class FancyInteger(Integer):313    def __str__(self):314        return 'I am the integer %d' % self.x315316def persistent_load(persid):317    if persid.startswith('the value '):318        value = int(persid.split()[2])319        return FancyInteger(value)320    else:321        raise pickle.UnpicklingError, 'Invalid persistent id'322323up.persistent_load = persistent_load324325j = up.load()326print j327```328329В модуле [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) атрибут `persistent_load` распаковщика также может быть установлен в список Python; в этом случае, когда распаковщик достигает постоянного идентификатора, строка постоянного идентификатора просто добавляется в этот список. Эта функциональность существует для того, чтобы поток данных pickle можно было «пронюхать» на предмет ссылок на объекты без фактического создания всех объектов в pickle. [8](https://python-all.ru/2.7/library/pickle.html#id18) Установка `persistent_load` в список обычно используется в сочетании с методом `noload()` на Unpickler.330331## 11.1.6. Создание подклассов Распаковщика332333По умолчанию распаковка импортирует любой класс, который найдет в данных pickle. Вы можете точно контролировать, что будет распаковано и что будет вызвано, настроив свой распаковщик. К сожалению, способ это сделать различается в зависимости от того, используете ли вы [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) или [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle). [9](https://python-all.ru/2.7/library/pickle.html#id19)334335В модуле [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) вам нужно создать подкласс от `Unpickler`, переопределив метод `load_global()`. `load_global()` должен читать две строки из потока данных pickle, где первая строка будет именем модуля, содержащего класс, а вторая – именем класса экземпляра. Затем он ищет класс, возможно импортируя модуль и извлекая атрибут, после чего добавляет найденное в стек распаковщика. Позже этот класс будет присвоен атрибуту `__class__` пустого класса, что является способом магического создания экземпляра без вызова [`__init__()`](https://python-all.ru/2.7/reference/datamodel.html#object.__init__) его класса. Ваша задача (если вы решите её принять) – сделать так, чтобы `load_global()` помещал в стек распаковщика известную безопасную версию любого класса, который вы считаете безопасным для распаковки. Создать такой класс – ваша забота. Или вы можете возбудить ошибку, если хотите запретить любую распаковку экземпляров. Если это звучит как хак, вы правы. Обратитесь к исходному коду, чтобы заставить это работать.336337С [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) дела обстоят немного чище, но ненамного. Чтобы контролировать, что будет распаковано, вы можете установить атрибут `find_global` распаковщика в функцию или `None`. Если это `None`, то любые попытки распаковать экземпляры возбудят `UnpicklingError`. Если это функция, то она должна принимать имя модуля и имя класса и возвращать соответствующий объект класса. Она отвечает за поиск класса и выполнение необходимых импортов, и может возбудить ошибку, чтобы предотвратить распаковку экземпляров этого класса.338339Мораль этой истории в том, что нужно быть очень осторожным с источником строк, которые ваше приложение распаковывает.340341## 11.1.7. Пример342343Для простейшего кода используйте функции `dump()` и `load()`. Обратите внимание, что самоссылающийся список корректно упаковывается и восстанавливается.344345```python346import pickle347348data1 = {'a': [1, 2.0, 3, 4+6j],349         'b': ('string', u'Unicode string'),350         'c': None}351352selfref_list = [1, 2, 3]353selfref_list.append(selfref_list)354355output = open('data.pkl', 'wb')356357# Сериализовать словарь с помощью протокола 0.358pickle.dump(data1, output)359360# Сериализовать список с использованием наивысшего доступного протокола.361pickle.dump(selfref_list, output, -1)362363output.close()364```365366Следующий пример считывает полученные сериализованные данные. При чтении файла, содержащего pickle, файл следует открывать в бинарном режиме, так как нельзя быть уверенным, какой формат использовался – ASCII или бинарный.367368```python369import pprint, pickle370371pkl_file = open('data.pkl', 'rb')372373data1 = pickle.load(pkl_file)374pprint.pprint(data1)375376data2 = pickle.load(pkl_file)377pprint.pprint(data2)378379pkl_file.close()380```381382Вот более крупный пример, показывающий, как изменить поведение упаковки для класса. Класс `TextReader` открывает текстовый файл и возвращает номер строки и содержимое строки каждый раз при вызове метода `readline()`. Если экземпляр `TextReader` упаковывается, сохраняются все атрибуты *кроме* файлового объекта. При распаковке экземпляра файл открывается заново и чтение продолжается с последней позиции. Методы [`__setstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__setstate__) и [`__getstate__()`](https://python-all.ru/2.7/library/pickle.html#object.__getstate__) используются для реализации такого поведения.383384```python385#!/usr/local/bin/python386387class TextReader:388    """Вывести и пронумеровать строки в текстовом файле."""389    def __init__(self, file):390        self.file = file391        self.fh = open(file)392        self.lineno = 0393394    def readline(self):395        self.lineno = self.lineno + 1396        line = self.fh.readline()397        if not line:398            return None399        if line.endswith("\n"):400            line = line[:-1]401        return "%d: %s" % (self.lineno, line)402403    def __getstate__(self):404        odict = self.__dict__.copy() # Скопировать словарь, так как он изменяется405        del odict['fh']              # Удалить запись дескриптора файла406        return odict407408    def __setstate__(self, dict):409        fh = open(dict['file'])      # Переоткрыть файл410        count = dict['lineno']       # Читать из файла...411        while count:                 # Пока счётчик строк не восстановится412            fh.readline()413            count = count - 1414        self.__dict__.update(dict)   # Обновить атрибуты415        self.fh = fh                 # Сохранить файловый объект416```417418Пример использования может выглядеть так:419420```python421>>> import TextReader422>>> obj = TextReader.TextReader("TextReader.py")423>>> obj.readline()424'1: #!/usr/local/bin/python'425>>> obj.readline()426'2: '427>>> obj.readline()428'3: class TextReader:'429>>> import pickle430>>> pickle.dump(obj, open('save.p', 'wb'))431```432433Чтобы убедиться, что [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) работает между процессами Python, запустите другой сеанс Python перед продолжением. Далее описанное может происходить как в том же процессе, так и в новом.434435```python436>>> import pickle437>>> reader = pickle.load(open('save.p', 'rb'))438>>> reader.readline()439'4:     """Print and number lines in a text file."""'440```441442> **См. также**443>444> **Модуль [`copy_reg`](https://python-all.ru/2.7/library/copy_reg.html#module-copy_reg)**445>446> Регистрация конструктора интерфейса pickle для расширенных типов.447>448> **Модуль [`shelve`](https://python-all.ru/2.7/library/shelve.html#module-shelve)**449>450> Индексированные базы данных объектов; использует [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle).451>452> **Модуль [`copy`](https://python-all.ru/2.7/library/copy.html#module-copy)**453>454> Поверхностное и глубокое копирование объектов.455>456> **Модуль [`marshal`](https://python-all.ru/2.7/library/marshal.html#module-marshal)**457>458> Высокопроизводительная сериализация встроенных типов.459460# 11.2. [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) – более быстрый [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle)461462Модуль [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) поддерживает сериализацию и десериализацию объектов Python, предоставляя интерфейс и функциональность, почти идентичные модулю [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle). Есть несколько различий, самое важное – производительность и возможность создания подклассов.463464Во-первых, [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) может быть до 1000 раз быстрее [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle), поскольку первый реализован на C. Во-вторых, в модуле [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) вызываемые объекты `Pickler()` и `Unpickler()` являются функциями, а не классами. Это означает, что их нельзя использовать для создания пользовательских подклассов упаковки и распаковки. Большинству приложений эта функциональность не нужна, и они могут воспользоваться значительно улучшенной производительностью модуля [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle).465466Поток данных pickle, создаваемый [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) и [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle), идентичен, поэтому можно использовать [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) и [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) взаимозаменяемо с существующими pickles. [10](https://python-all.ru/2.7/library/pickle.html#id20)467468Существуют дополнительные небольшие различия в API между [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) и [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle), однако для большинства приложений они взаимозаменяемы. Более подробная документация приведена в документации модуля [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle), которая включает список задокументированных различий.469470Сноски471472**[1](https://python-all.ru/2.7/library/pickle.html#id1)**473474Не путайте это с модулем [`marshal`](https://python-all.ru/2.7/library/marshal.html#module-marshal)475476**[2](https://python-all.ru/2.7/library/pickle.html#id2)**477478В модуле [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) эти вызываемые объекты являются классами, которые можно наследовать для настройки поведения. Однако в модуле [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle) эти вызываемые объекты являются фабричными функциями и поэтому не могут быть унаследованы. Одна из распространённых причин создания подкласса – контроль того, какие объекты можно распаковать. Подробнее см. раздел [Наследование распаковщиков](https://python-all.ru/2.7/library/pickle.html#pickle-sub).479480**[3](https://python-all.ru/2.7/library/pickle.html#id3)**481482*Предупреждение*: это предназначено для упаковки нескольких объектов без промежуточных изменений объектов или их частей. Если изменить объект, а затем упаковать его снова, используя тот же экземпляр `Pickler`, объект не упаковывается заново – упаковывается ссылка на него, и `Unpickler` вернёт старое значение, а не изменённое. Здесь есть две проблемы: (1) обнаружение изменений и (2) маршалинг минимального набора изменений. Сборка мусора также может стать проблемой.483484**[4](https://python-all.ru/2.7/library/pickle.html#id4)**485486Возникающее исключение, скорее всего, будет [`ImportError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ImportError) или [`AttributeError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.AttributeError), но может быть и другим.487488**[5](https://python-all.ru/2.7/library/pickle.html#id5)**489490Эти методы также можно использовать для реализации копирования экземпляров классов.491492**[6](https://python-all.ru/2.7/library/pickle.html#id6)**493494Этот протокол также используется операциями поверхностного и глубокого копирования, определёнными в модуле [`copy`](https://python-all.ru/2.7/library/copy.html#module-copy).495496**[7](https://python-all.ru/2.7/library/pickle.html#id7)**497498Реальный механизм связывания этих пользовательских функций немного отличается для [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) и [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle). Приведённое здесь описание работает одинаково для обеих реализаций. Пользователи модуля [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle) также могут использовать наследование для достижения тех же результатов, переопределяя методы `persistent_id()` и `persistent_load()` в производных классах.499500**[8](https://python-all.ru/2.7/library/pickle.html#id8)**501502Оставим вас с образом Гвидо и Джима, сидящих и нюхающих пикули в своих гостиных.503504**[9](https://python-all.ru/2.7/library/pickle.html#id9)**505506Предостережение: описанные здесь механизмы используют внутренние атрибуты и методы, которые могут измениться в будущих версиях Python. Мы намерены когда-нибудь предоставить общий интерфейс для управления этим поведением, который будет работать как с [`pickle`](https://python-all.ru/2.7/library/pickle.html#module-pickle), так и с [`cPickle`](https://python-all.ru/2.7/library/pickle.html#module-cPickle).507508**[10](https://python-all.ru/2.7/library/pickle.html#id10)**509510Поскольку формат данных pickle на самом деле является крошечным стековым языком программирования и допускает некоторую свободу в кодировании определённых объектов, возможно, что два модуля создают разные потоки данных для одних и тех же входных объектов. Однако гарантируется, что они всегда смогут читать потоки данных друг друга.511