# `pickle` — Python object serialization

Вихідний код: Lib/pickle.py

Модуль `pickle` реалізує двійкові протоколи для серіалізації та десеріалізації структури об’єктів Python. «Pickling» - це процес, за допомогою якого ієрархія об’єктів Python перетворюється на потік байтів, а «unpickling» - це зворотна операція, за допомогою якої потік байтів (з binary file або bytes-like object) перетворюється назад в ієрархію об’єктів. Травлення (і розбирання) також відоме як «серіалізація», «маршалінг», [1] або «зведення»; однак, щоб уникнути плутанини, тут використовуються терміни «маринування» та «розмаринування».

Попередження

Модуль `pickle` не захищений. Вилучайте лише дані, яким довіряєте.

Можна створити шкідливі дані pickle, які виконуватимуть довільний код під час unpickling. Ніколи не видаляйте дані, які могли надійти з ненадійного джерела або які могли бути підроблені.

Розгляньте можливість підписати дані за допомогою `hmac`, якщо вам потрібно переконатися, що вони не були змінені.

Більш безпечні формати серіалізації, такі як `json`, можуть бути більш доречними, якщо ви обробляєте ненадійні дані. Перегляньте Порівняння з json.

## Зв’язок з іншими модулями Python

### Порівняння з `маршалом`

Python має примітивніший модуль серіалізації під назвою `marshal`, але загалом `pickle` має завжди бути кращим способом серіалізації об’єктів Python. `marshal` існує в основному для підтримки файлів `.pyc` Python.

Модуль `pickle` відрізняється від `marshal` кількома суттєвими ознаками:

- Модуль `pickle` відстежує об’єкти, які він уже серіалізував, так що пізніші посилання на той самий об’єкт не будуть серіалізовані знову. `marshal` цього не робить.

  Це стосується як рекурсивних об’єктів, так і спільного використання об’єктів. Рекурсивні об’єкти - це об’єкти, які містять посилання на себе. Вони не обробляються маршалом, і фактично спроба маршалу рекурсивних об’єктів призведе до збою вашого інтерпретатора Python. Спільне використання об’єктів відбувається, коли існує кілька посилань на той самий об’єкт у різних місцях ієрархії об’єктів, що серіалізується. `pickle` зберігає такі об’єкти лише один раз і гарантує, що всі інші посилання вказують на головну копію. Спільні об’єкти залишаються спільними, що може бути дуже важливим для змінних об’єктів.

- `marshal` не можна використовувати для серіалізації визначених користувачем класів та їх екземплярів. `pickle` може прозоро зберігати та відновлювати екземпляри класу, однак визначення класу має бути імпортованим і знаходитись у тому самому модулі, що й під час зберігання об’єкта.

- Формат серіалізації `marshal` не гарантовано переноситься між версіями Python. Оскільки основним завданням у житті є підтримка файлів `.pyc`, розробники Python залишають за собою право змінювати формат серіалізації несумісними способами, якщо виникне така потреба. Формат серіалізації `pickle` гарантовано буде зворотно сумісним з усіма випусками Python за умови, що вибрано сумісний протокол pickle, а код піклування та депіклування враховує відмінності типів Python 2 і Python 3, якщо ваші дані перетинають цю унікальну межу мови зміни порушення. .

### Порівняння з `json`

There are fundamental differences between the pickle protocols and JSON (JavaScript Object Notation):

- JSON — це формат текстової серіалізації (він виводить текст Юнікод, хоча здебільшого він потім кодується у `utf-8`), тоді як pickle — це двійковий формат серіалізації;

- JSON читається людиною, а pickle – ні;

- JSON є сумісним і широко використовується за межами екосистеми Python, тоді як pickle є специфічним для Python;

- За замовчуванням JSON може представляти лише підмножину вбудованих типів Python, а не спеціальні класи; pickle може представляти надзвичайно велику кількість типів Python (багато з них автоматично, завдяки розумному використанню можливостей інтроспекції Python; складні випадки можна вирішити шляхом впровадження спеціальних API об’єктів);

- На відміну від pickle, десеріалізація ненадійного JSON сама по собі не створює вразливості виконання довільного коду.

Дивись також

Модуль `json`: стандартний бібліотечний модуль, який дозволяє серіалізацію та десеріалізацію JSON.

## Формат потоку даних

The data format used by `pickle` is Python-specific. This has the advantage that there are no restrictions imposed by external standards such as JSON (which can’t represent pointer sharing); however it means that non-Python programs may not be able to reconstruct pickled Python objects.

За замовчуванням формат даних `pickle` використовує відносно компактне двійкове представлення. Якщо вам потрібні оптимальні характеристики розміру, ви можете ефективно стиснути мариновані дані.

Модуль `pickletools` містить інструменти для аналізу потоків даних, згенерованих `pickle`. Вихідний код `pickletools` містить численні коментарі щодо кодів операцій, які використовуються протоколами pickle.

На даний момент існує 6 різних протоколів, які можна використовувати для маринування. Чим вищий протокол використовується, тим новіша версія Python потрібна для читання створеного пікле.

- Протокол версії 0 — це оригінальний «людиночитаний» протокол, який зворотно сумісний із попередніми версіями Python.

- Протокол версії 1 — це старий двійковий формат, який також сумісний із попередніми версіями Python.

- Протокол версії 2 був представлений у Python 2.3. Він забезпечує набагато ефективніше маринування класів нового стилю. Зверніться до PEP 307, щоб отримати інформацію про покращення, внесені протоколом 2.

- Протокол версії 3 додано в Python 3.0. Він має явну підтримку об’єктів `bytes` і не може бути скасований Python 2.x. Це був протокол за замовчуванням у Python 3.0-3.7.

- Protocol version 4 was added in Python 3.4. It adds support for very large objects, pickling more kinds of objects, and some data format optimizations. This was the default protocol in Python 3.8–3.13. Refer to PEP 3154 for information about improvements brought by protocol 4.

- Protocol version 5 was added in Python 3.8. It adds support for out-of-band data and speedup for in-band data. It is the default protocol starting with Python 3.14. Refer to PEP 574 for information about improvements brought by protocol 5.

Примітка

Серіалізація є більш примітивним поняттям, ніж стійкість; хоча `pickle` читає та записує файлові об’єкти, він не вирішує проблему іменування постійних об’єктів, ані (навіть більш складну) проблему одночасного доступу до постійних об’єктів. Модуль `pickle` може перетворити складний об’єкт у потік байтів, і він може перетворити потік байтів в об’єкт із такою ж внутрішньою структурою. Мабуть, найочевидніша річ, яку можна зробити з цими потоками байтів, — це записати їх у файл, але також можливо надіслати їх через мережу або зберегти в базі даних. Модуль `shelve` забезпечує простий інтерфейс для вибору та вилучення об’єктів у файлах бази даних у стилі DBM.

## Інтерфейс модуля

Щоб серіалізувати ієрархію об’єктів, ви просто викликаєте функцію `dumps()`. Так само, щоб десеріалізувати потік даних, ви викликаєте функцію `loads()`. Однак, якщо ви хочете більше контролювати серіалізацію та десеріалізацію, ви можете створити об’єкт `Pickler` або `Unpickler` відповідно.

Модуль `pickle` надає такі константи:

pickle.HIGHEST_PROTOCOL

  Ціле число, найвища доступна версія протоколу. Це значення можна передати як значення protocol до функцій `dump()` і `dumps()`, а також до конструктора `Pickler`.

pickle.DEFAULT_PROTOCOL

  An integer, the default protocol version used for pickling. May be less than `HIGHEST_PROTOCOL`. Currently the default protocol is 5, introduced in Python 3.8 and incompatible with previous versions. This version introduces support for out-of-band buffers, where PEP 3118-compatible data can be transmitted separately from the main pickle stream.

  Змінено в версії 3.0: Стандартний протокол – 3.

  Змінено в версії 3.8: Стандартний протокол – 4.

  Змінено в версії 3.14: The default protocol is 5.

Модуль `pickle` надає такі функції, щоб зробити процес маринування зручнішим:

pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)

  Запишіть виділене представлення об’єкта obj у відкритий file object file. Це еквівалентно `Pickler(file, protocol).dump(obj)`.

  Аргументи file, protocol, fix_imports і buffer_callback мають те саме значення, що й у конструкторі `Pickler`.

  Змінено в версії 3.8: Додано аргумент buffer_callback.

pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)

  Повернути відібране представлення об’єкта obj як об’єкт `bytes` замість запису його у файл.

  Аргументи protocol, fix_imports і buffer_callback мають те саме значення, що й у конструкторі `Pickler`.

  Змінено в версії 3.8: Додано аргумент buffer_callback.

pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

  Зчитувати виділене представлення об’єкта з відкритого file object file і повертати відновлену ієрархію об’єктів, указану в ньому. Це еквівалентно `Unpickler(file).load()`.

  Версія протоколу pickle визначається автоматично, тому аргумент протоколу не потрібен. Байти, що перебувають після виділеного представлення об’єкта, ігноруються.

  Аргументи file, fix_imports, encoding, errors, strict і buffers мають те саме значення, що й у конструкторі `Unpickler`.

  Змінено в версії 3.8: Додано аргумент buffers.

pickle.loads(data, /, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

  Повертає відновлену ієрархію об’єктів маринованого представлення даних об’єкта. data має бути bytes-like object.

  Версія протоколу pickle визначається автоматично, тому аргумент протоколу не потрібен. Байти, що перебувають після виділеного представлення об’єкта, ігноруються.

  Аргументи fix_imports, encoding, errors, strict і buffers мають те саме значення, що й у конструкторі `Unpickler`.

  Змінено в версії 3.8: Додано аргумент buffers.

Модуль `pickle` визначає три винятки:

exception pickle.PickleError

  Common base class for the other pickling exceptions. It inherits from `Exception`.

exception pickle.PicklingError

  Error raised when an unpicklable object is encountered by `Pickler`. It inherits from `PickleError`.

  Зверніться до Що можна маринувати і не квашети?, щоб дізнатися, які види об’єктів можна маринувати.

exception pickle.UnpicklingError

  Error raised when there is a problem unpickling an object, such as a data corruption or a security violation. It inherits from `PickleError`.

  Зауважте, що інші винятки також можуть виникати під час видалення, включаючи (але не обов’язково обмежуючись ними) AttributeError, EOFError, ImportError та IndexError.

Модуль `pickle` експортує три класи, `Pickler`, `Unpickler` і `PickleBuffer`:

class pickle.Pickler(file, protocol=None, *, fix_imports=True, buffer_callback=None)

  Це бере двійковий файл для запису потоку даних pickle.

  Необов’язковий аргумент protocol, ціле число, повідомляє піклеру використовувати заданий протокол; підтримувані протоколи від 0 до `HIGHEST_PROTOCOL`. Якщо не вказано, типовим є `DEFAULT_PROTOCOL`. Якщо вказано від’ємне число, вибирається `HIGHEST_PROTOCOL`.

  Аргумент file повинен мати метод write(), який приймає однобайтовий аргумент. Таким чином, це може бути файл на диску, відкритий для двійкового запису, екземпляр `io.BytesIO` або будь-який інший спеціальний об’єкт, який відповідає цьому інтерфейсу.

  Якщо fix_imports має значення true, а protocol — менше 3, pickle спробує зіставити нові імена Python 3 зі старими назвами модулів, які використовуються в Python 2, щоб потік даних pickle можна було читати за допомогою Python 2.

  If buffer_callback is `None` (the default), buffer views are serialized into file as part of the pickle stream.

  If buffer_callback is not `None`, then it can be called any number of times with a buffer view. If the callback returns a false value (such as `None`), the given buffer is out-of-band; otherwise the buffer is serialized in-band, i.e. inside the pickle stream.

  It is an error if buffer_callback is not `None` and protocol is `None` or smaller than 5.

  Змінено в версії 3.8: Додано аргумент buffer_callback.

  dump(obj)

    Запишіть виділене представлення obj до відкритого файлового об’єкта, наданого в конструкторі.

  persistent_id(obj)

    За замовчуванням нічого не робити. Це існує, тому підклас може замінити його.

    Якщо `persistent_id()` повертає `None`, obj маринується як зазвичай. Будь-яке інше значення змушує `Pickler` видати повернуте значення як постійний ідентифікатор для obj. Значення цього постійного ідентифікатора має бути визначено `Unpickler.persistent_load()`. Зауважте, що значення, яке повертає `persistent_id()`, не може мати постійний ідентифікатор.

    Перегляньте Постійність зовнішніх об’єктів для деталей та прикладів використання.

    Змінено в версії 3.13: Add the default implementation of this method in the C implementation of `Pickler`.

  dispatch_table

    A pickler object’s dispatch table is a registry of reduction functions of the kind which can be declared using `copyreg.pickle()`. It is a mapping whose keys are classes and whose values are reduction functions. A reduction function takes a single argument of the associated class and should conform to the same interface as a `__reduce__()` method.

    За замовчуванням об’єкт pickler не матиме атрибута `dispatch_table`, натомість він використовуватиме глобальну таблицю відправлення, якою керує модуль `copyreg`. Однак, щоб налаштувати травлення для певного об’єкта піклеру, можна встановити атрибут `dispatch_table` на об’єкт, подібний до dict. Крім того, якщо підклас `Pickler` має атрибут `dispatch_table`, тоді він використовуватиметься як типова таблиця відправлення для екземплярів цього класу.

    Перегляньте Таблиці відправлення приклади використання.

    Added in version 3.3.

  reducer_override(obj)

    Special reducer that can be defined in `Pickler` subclasses. This method has priority over any reducer in the `dispatch_table`. It should conform to the same interface as a `__reduce__()` method, and can optionally return `NotImplemented` to fallback on `dispatch_table`-registered reducers to pickle `obj`.

    Детальний приклад див. Спеціальне скорочення для типів, функцій та інших об’єктів.

    Added in version 3.8.

  fast

    Застаріле. Увімкнути швидкий режим, якщо встановлено справжнє значення. Швидкий режим вимикає використання memo, таким чином прискорюючи процес маринування, не генеруючи зайвих кодів операцій PUT. Його не слід використовувати з об’єктами, що посилаються на себе, інакше призведе до безкінечної рекурсії `Pickler`.

    Використовуйте `pickletools.optimize()`, якщо вам потрібні більш компактні соління.

  clear_memo()

    Clears the pickler’s «memo».

    The memo is the data structure that remembers which objects the pickler has already seen, so that shared or recursive objects are pickled by reference and not by value. This method is useful when re-using picklers.

class pickle.Unpickler(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

  Це бере двійковий файл для читання потоку даних pickle.

  Версія протоколу pickle визначається автоматично, тому аргумент протоколу не потрібен.

  Аргумент file повинен мати три методи: метод read(), який приймає цілочисельний аргумент, метод readinto(), який приймає аргумент буфера, і метод readline(), який не потребує аргументів, як у Інтерфейс `io.BufferedIOBase`. Таким чином, file може бути файлом на диску, відкритим для двійкового читання, об’єктом `io.BytesIO` або будь-яким іншим спеціальним об’єктом, який відповідає цьому інтерфейсу.

  Необов’язкові аргументи fix_imports, encoding і errors використовуються для керування підтримкою сумісності для потоку pickle, створеного Python 2. Якщо fix_imports має значення true, pickle спробує зіставити старі імена Python 2 з новими іменами, які використовуються у Python 3. кодування та помилки повідомляють pickle, як декодувати 8-бітні екземпляри рядків, вибрані Python 2; за замовчуванням вони мають значення «ASCII» і «strict» відповідно. Кодуванням може бути «байт» для читання цих 8-бітних екземплярів рядка як об’єктів bytes. Використання `encoding='latin1'` потрібне для видалення масивів NumPy і екземплярів `datetime`, `date` і `time`, вибраних Python 2.

  If buffers is `None` (the default), then all data necessary for deserialization must be contained in the pickle stream. This means that the buffer_callback argument was `None` when a `Pickler` was instantiated (or when `dump()` or `dumps()` was called).

  If buffers is not `None`, it should be an iterable of buffer-enabled objects that is consumed each time the pickle stream references an out-of-band buffer view. Such buffers have been given in order to the buffer_callback of a Pickler object.

  Змінено в версії 3.8: Додано аргумент buffers.

  load()

    Зчитувати виділене представлення об’єкта з відкритого файлового об’єкта, наданого в конструкторі, і повертати відновлену ієрархію об’єктів, указану в ньому. Байти, які перебувають після виділеного представлення об’єкта, ігноруються.

  persistent_load(pid)

    Викликати `UnpicklingError` за замовчуванням.

    Якщо визначено, `persistent_load()` має повертати об’єкт, указаний постійним ідентифікатором pid. Якщо виявлено недійсний постійний ідентифікатор, має бути викликано `UnpicklingError`.

    Перегляньте Постійність зовнішніх об’єктів для деталей та прикладів використання.

    Змінено в версії 3.13: Add the default implementation of this method in the C implementation of `Unpickler`.

  find_class(module, name)

    Імпортуйте module, якщо необхідно, і поверніть з нього об’єкт із назвою name, де аргументи module і name є об’єктами `str`. Зверніть увагу, на відміну від назви, `find_class()` також використовується для пошуку функцій.

    Підкласи можуть замінити це, щоб отримати контроль над тим, який тип об’єктів і як їх можна завантажувати, потенційно зменшуючи ризики безпеки. Зверніться до Обмеження Globals для деталей.

    Викликає подію аудиту `pickle.find_class` з аргументами `module`, `name`.

class pickle.PickleBuffer(buffer)

  Обгортка для буфера, що представляє дані, які можна вибрати. buffer має бути об’єктом, що надає буфер, наприклад bytes-like object або N-вимірним масивом.

  `PickleBuffer` сам є постачальником буфера, тому його можна передати іншим API, які очікують об’єкта, що надає буфер, наприклад `memoryview`.

  Об’єкти `PickleBuffer` можна серіалізувати лише за допомогою протоколу pickle версії 5 або вище. Вони підходять для позасмугової серіалізації.

  Added in version 3.8.

  raw()

    Повертає `memoryview` області пам’яті, що лежить в основі цього буфера. Повернений об’єкт є одновимірним C-суміжним представленням пам’яті у форматі `B` (байти без знаку). `BufferError` виникає, якщо буфер не суміжний ні на C, ні на Fortran.

  release()

    Вивільніть базовий буфер, відкритий об’єктом PickleBuffer.

## Що можна маринувати і не квашети?

Маринувати можна такі види:

- built-in constants (`None`, `True`, `False`, `Ellipsis`, and `NotImplemented`);

- цілі числа, числа з плаваючою комою, комплексні числа;

- рядки, байти, байтові масиви;

- кортежі, списки, набори та словники, що містять лише об’єкти, які можна вибирати;

- функції (вбудовані та визначені користувачем), доступні з верхнього рівня модуля (за допомогою `def`, а не `lambda`);

- класи, доступні з верхнього рівня модуля;

- instances of such classes whose the result of calling `__getstate__()` is picklable (see section Примірники класу маринування for details).

Спроби маринувати об’єкти, які неможливо вибрати, викличуть виняток `PicklingError`; коли це трапляється, невизначену кількість байтів, можливо, уже було записано до основного файлу. Спроба відібрати високорекурсивну структуру даних може перевищити максимальну глибину рекурсії, у цьому випадку виникне `RecursionError`. Ви можете обережно збільшити це обмеження за допомогою `sys.setrecursionlimit()`.

Зауважте, що функції (вбудовані та визначені користувачем) вибираються за повним qualified name, а не за значенням. [2] Це означає, що виділяється лише назва функції, а також назва модуля та класів, що містять. Ні код функції, ні будь-які її атрибути функції не мариновані. Таким чином, визначальний модуль має бути імпортованим у середовищі unpickling, і модуль має містити названий об’єкт, інакше буде створено виняток. [3]

Подібним чином, класи вибираються за повним іменем, тому застосовуються ті самі обмеження в середовищі розбирання. Зауважте, що жоден із коду чи даних класу не вибирається, тому в наступному прикладі атрибут класу `attr` не відновлюється в середовищі розбирання:

    class Foo:
        attr = 'A class attribute'

    picklestring = pickle.dumps(Foo)

Через ці обмеження функції та класи, які можна вибрати, повинні бути визначені на верхньому рівні модуля.

Similarly, when class instances are pickled, their class’s code and data are not pickled along with them. Only the instance data are pickled. This is done on purpose, so you can fix bugs in a class or add methods to the class and still load objects that were created with an earlier version of the class. If you plan to have long-lived objects that will see many versions of a class, it may be worthwhile to put a version number in the objects so that suitable conversions can be made by the class’s `__setstate__()` method.

## Примірники класу маринування

У цьому розділі ми описуємо загальні механізми, доступні вам для визначення, налаштування та контролю того, як екземпляри класу вибираються та не вибираються.

In most cases, no additional code is needed to make instances picklable. By default, pickle will retrieve the class and the attributes of an instance via introspection. When a class instance is unpickled, its `__init__()` method is usually not invoked. The default behaviour first creates an uninitialized instance and then restores the saved attributes. The following code shows an implementation of this behaviour:

    def save(obj):
        return (obj.__class__, obj.__dict__)

    def restore(cls, attributes):
        obj = cls.__new__(cls)
        obj.__dict__.update(attributes)
        return obj

Класи можуть змінювати типову поведінку, надаючи один або декілька спеціальних методів:

object.__getnewargs_ex__()

  У протоколах 2 і новіших класи, які реалізують метод `__getnewargs_ex__()`, можуть диктувати значення, що передаються в метод `__new__()` після видалення. Метод має повертати пару «(args, kwargs)», де args — це кортеж позиційних аргументів, а kwargs — словник іменованих аргументів для побудови об’єкта. Вони будуть передані в метод `__new__()` після видалення.

  Ви повинні застосувати цей метод, якщо метод `__new__()` вашого класу вимагає аргументів лише з ключовими словами. В іншому випадку для сумісності рекомендується реалізувати `__getnewargs__()`.

  Змінено в версії 3.6: `__getnewargs_ex__()` тепер використовується в протоколах 2 і 3.

object.__getnewargs__()

  Цей метод виконує таку саму мету, як `__getnewargs_ex__()`, але підтримує лише позиційні аргументи. Він має повертати кортеж аргументів `args`, який буде передано методу `__new__()` після видалення.

  `__getnewargs__()` не буде викликано, якщо `__getnewargs_ex__()` визначено.

  Змінено в версії 3.6: До Python 3.6 `__getnewargs__()` викликався замість `__getnewargs_ex__()` у протоколах 2 і 3.

object.__getstate__()

  Classes can further influence how their instances are pickled by overriding the method `__getstate__()`. It is called and the returned object is pickled as the contents for the instance, instead of a default state. There are several cases:

  - For a class that has no instance `__dict__` and no `__slots__`, the default state is `None`.

  - For a class that has an instance `__dict__` and no `__slots__`, the default state is `self.__dict__`.

  - For a class that has an instance `__dict__` and `__slots__`, the default state is a tuple consisting of two dictionaries: `self.__dict__`, and a dictionary mapping slot names to slot values. Only slots that have a value are included in the latter.

  - For a class that has `__slots__` and no instance `__dict__`, the default state is a tuple whose first item is `None` and whose second item is a dictionary mapping slot names to slot values described in the previous bullet.

  Змінено в версії 3.11: Added the default implementation of the `__getstate__()` method in the `object` class.

object.__setstate__(state)

  Якщо під час розбирання клас визначає `__setstate__()`, він викликається зі станом unpickled. У цьому випадку немає вимоги, щоб об’єкт стану був словником. В іншому випадку маринований стан має бути словником, а його елементи призначаються словнику нового екземпляра.

  Примітка

  If `__reduce__()` returns a state with value `None` at pickling, the `__setstate__()` method will not be called upon unpickling.

Refer to the section Обробка об’єктів із збереженням стану for more information about how to use the methods `__getstate__()` and `__setstate__()`.

Примітка

At unpickling time, some methods like `__getattr__()`, `__getattribute__()`, or `__setattr__()` may be called upon the instance. In case those methods rely on some internal invariant being true, the type should implement `__new__()` to establish such an invariant, as `__init__()` is not called when unpickling an instance.

As we shall see, pickle does not use directly the methods described above. In fact, these methods are part of the copy protocol which implements the `__reduce__()` special method. The copy protocol provides a unified interface for retrieving the data necessary for pickling and copying objects. [4]

Although powerful, implementing `__reduce__()` directly in your classes is error prone. For this reason, class designers should use the high-level interface (i.e., `__getnewargs_ex__()`, `__getstate__()` and `__setstate__()`) whenever possible. We will show, however, cases where using `__reduce__()` is the only option or leads to more efficient pickling or both.

object.__reduce__()

  На даний момент інтерфейс визначається наступним чином. Метод `__reduce__()` не приймає аргументів і повертає або рядок, або, бажано, кортеж (повернений об’єкт часто називають «зменшеним значенням»).

  Якщо повертається рядок, цей рядок слід інтерпретувати як назву глобальної змінної. Це має бути локальне ім’я об’єкта відносно його модуля; модуль pickle шукає простір імен модуля, щоб визначити модуль об’єкта. Така поведінка, як правило, корисна для одиночних користувачів.

  Коли повертається кортеж, він має містити від двох до шести елементів. Необов’язкові елементи можна або пропустити, або в якості їхнього значення можна вказати `None`. Семантика кожного елемента в порядку:

  - Викликаний об’єкт, який буде викликано для створення початкової версії об’єкта.

  - Кортеж аргументів для викликаного об’єкта. Порожній кортеж повинен бути наданий, якщо викликаний не приймає жодних аргументів.

  - Необов’язково, стан об’єкта, який буде передано методу `__setstate__()` об’єкта, як описано раніше. Якщо об’єкт не має такого методу, значення має бути словником, і воно буде додано до атрибута об’єкта `__dict__`.

  - Optionally, an iterator (and not a sequence) yielding successive items. These items will be appended to the object either using `obj.append(item)` or, in batch, using `obj.extend(list_of_items)`. This is primarily used for list subclasses, but may be used by other classes as long as they have append and extend methods with the appropriate signature. (Whether `append()` or `extend()` is used depends on which pickle protocol version is used as well as the number of items to append, so both must be supported.)

  - Необов’язково, ітератор (не послідовність), що дає послідовні пари ключ-значення. Ці елементи будуть збережені в об’єкті за допомогою `obj[key] = value`. Це в основному використовується для підкласів словників, але може використовуватися іншими класами, якщо вони реалізують `__setitem__()`.

  - Необов’язково, викликається з підписом `(obj, state)`. Цей виклик дозволяє користувачеві програмно керувати поведінкою оновлення стану конкретного об’єкта замість використання статичного методу `obj` `__setstate__()`. Якщо не `None`, цей виклик матиме пріоритет над `obj` `__setstate__()`.

    Added in version 3.8: Додано необов’язковий шостий елемент кортежу, `(obj, state)`.

object.__reduce_ex__(protocol)

  В якості альтернативи можна визначити метод `__reduce_ex__()`. Єдина відмінність полягає в тому, що цей метод має приймати один цілий аргумент, версію протоколу. Якщо визначено, pickle віддасть перевагу цьому методу `__reduce__()`. Крім того, `__reduce__()` автоматично стає синонімом розширеної версії. Основним використанням цього методу є надання зворотно сумісних значень зменшення для старіших випусків Python.

### Постійність зовнішніх об’єктів

На користь збереження об’єкта модуль `pickle` підтримує поняття посилання на об’єкт за межами марінованого потоку даних. На такі об’єкти посилається постійний ідентифікатор, який має бути або рядком буквено-цифрових символів (для протоколу 0) [5], або просто довільним об’єктом (для будь-якого новішого протоколу).

Роздільна здатність таких постійних ідентифікаторів не визначається модулем `pickle`; він делегує це вирішення визначеним користувачем методам pickler і unpickler, `persistent_id()` і `persistent_load()` відповідно.

Щоб вибирати об’єкти, які мають зовнішній постійний ідентифікатор, засіб вибору повинен мати спеціальний метод `persistent_id()`, який приймає об’єкт як аргумент і повертає «Немає» або постійний ідентифікатор для цього об’єкта. Коли повертається `None`, піклер просто маринує об’єкт як зазвичай. Коли повертається рядок постійного ідентифікатора, засіб вибору виділяє цей об’єкт разом із маркером, щоб засіб вилучення розпізнавало його як постійний ідентифікатор.

Щоб розібрати зовнішні об’єкти, розбірник повинен мати спеціальний метод `persistent_load()`, який приймає об’єкт постійного ідентифікатора та повертає об’єкт, на який посилається.

Ось вичерпний приклад, який демонструє, як постійний ідентифікатор можна використовувати для маринування зовнішніх об’єктів за посиланням.

    # Simple example presenting how persistent ID can be used to pickle
    # external objects by reference.

    import pickle
    import sqlite3
    from collections import namedtuple

    # Simple class representing a record in our database.
    MemoRecord = namedtuple("MemoRecord", "key, task")

    class DBPickler(pickle.Pickler):

        def persistent_id(self, obj):
            # Instead of pickling MemoRecord as a regular class instance, we emit a
            # persistent ID.
            if isinstance(obj, MemoRecord):
                # Here, our persistent ID is simply a tuple, containing a tag and a
                # key, which refers to a specific record in the database.
                return ("MemoRecord", obj.key)
            else:
                # If obj does not have a persistent ID, return None. This means obj
                # needs to be pickled as usual.
                return None

    class DBUnpickler(pickle.Unpickler):

        def __init__(self, file, connection):
            super().__init__(file)
            self.connection = connection

        def persistent_load(self, pid):
            # This method is invoked whenever a persistent ID is encountered.
            # Here, pid is the tuple returned by DBPickler.
            cursor = self.connection.cursor()
            type_tag, key_id = pid
            if type_tag == "MemoRecord":
                # Fetch the referenced record from the database and return it.
                cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),))
                key, task = cursor.fetchone()
                return MemoRecord(key, task)
            else:
                # Always raises an error if you cannot return the correct object.
                # Otherwise, the unpickler will think None is the object referenced
                # by the persistent ID.
                raise pickle.UnpicklingError("unsupported persistent object")

    def main():
        import io
        import pprint

        # Initialize and populate our database.
        conn = sqlite3.connect(":memory:")
        cursor = conn.cursor()
        cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)")
        tasks = (
            'give food to fish',
            'prepare group meeting',
            'fight with a zebra',
            )
        for task in tasks:
            cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,))

        # Fetch the records to be pickled.
        cursor.execute("SELECT * FROM memos")
        memos = [MemoRecord(key, task) for key, task in cursor]
        # Save the records using our custom DBPickler.
        file = io.BytesIO()
        DBPickler(file).dump(memos)

        print("Pickled records:")
        pprint.pprint(memos)

        # Update a record, just for good measure.
        cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1")

        # Load the records from the pickle data stream.
        file.seek(0)
        memos = DBUnpickler(file, conn).load()

        print("Unpickled records:")
        pprint.pprint(memos)

    if __name__ == '__main__':
        main()

### Таблиці відправлення

Якщо ви хочете налаштувати маринування деяких класів, не порушуючи будь-який інший код, який залежить від маринування, тоді можна створити піклер із приватною таблицею відправлення.

The global dispatch table managed by the `copyreg` module is available as `copyreg.dispatch_table`. Therefore, one may choose to use a modified copy of `copyreg.dispatch_table` as a private dispatch table.

Наприклад

    f = io.BytesIO()
    p = pickle.Pickler(f)
    p.dispatch_table = copyreg.dispatch_table.copy()
    p.dispatch_table[SomeClass] = reduce_SomeClass

створює екземпляр `pickle.Pickler` із приватною таблицею відправлення, яка спеціально обробляє клас `SomeClass`. Як альтернатива, код:

    class MyPickler(pickle.Pickler):
        dispatch_table = copyreg.dispatch_table.copy()
        dispatch_table[SomeClass] = reduce_SomeClass
    f = io.BytesIO()
    p = MyPickler(f)

робить те саме, але всі екземпляри `MyPickler` за замовчуванням спільно використовуватимуть приватну таблицю відправлення. З іншого боку, код

    copyreg.pickle(SomeClass, reduce_SomeClass)
    f = io.BytesIO()
    p = pickle.Pickler(f)

змінює глобальну таблицю відправлення, яку використовують усі користувачі модуля `copyreg`.

### Обробка об’єктів із збереженням стану

Here’s an example that shows how to modify pickling behavior for a class. The `TextReader` class below opens a text file, and returns the line number and line contents each time its `readline()` method is called. If a `TextReader` instance is pickled, all attributes except the file object member are saved. When the instance is unpickled, the file is reopened, and reading resumes from the last location. The `__setstate__()` and `__getstate__()` methods are used to implement this behavior.

    class TextReader:
        """Print and number lines in a text file."""

        def __init__(self, filename):
            self.filename = filename
            self.file = open(filename)
            self.lineno = 0

        def readline(self):
            self.lineno += 1
            line = self.file.readline()
            if not line:
                return None
            if line.endswith('\n'):
                line = line[:-1]
            return "%i: %s" % (self.lineno, line)

        def __getstate__(self):
            # Copy the object's state from self.__dict__ which contains
            # all our instance attributes. Always use the dict.copy()
            # method to avoid modifying the original state.
            state = self.__dict__.copy()
            # Remove the unpicklable entries.
            del state['file']
            return state

        def __setstate__(self, state):
            # Restore instance attributes (i.e., filename and lineno).
            self.__dict__.update(state)
            # Restore the previously opened file's state. To do so, we need to
            # reopen it and read from it until the line count is restored.
            file = open(self.filename)
            for _ in range(self.lineno):
                file.readline()
            # Finally, save the file.
            self.file = file

Зразок використання може бути приблизно таким:

    >>> reader = TextReader("hello.txt")
    >>> reader.readline()
    '1: Hello world!'
    >>> reader.readline()
    '2: I am line number two.'
    >>> new_reader = pickle.loads(pickle.dumps(reader))
    >>> new_reader.readline()
    '3: Goodbye!'

## Спеціальне скорочення для типів, функцій та інших об’єктів

Added in version 3.8.

Іноді `dispatch_table` може бути недостатньо гнучким. Зокрема, ми можемо захотіти налаштувати маринування на основі іншого критерію, ніж тип об’єкта, або ми можемо захотіти налаштувати маринування функцій і класів.

For those cases, it is possible to subclass from the `Pickler` class and implement a `reducer_override()` method. This method can return an arbitrary reduction tuple (see `__reduce__()`). It can alternatively return `NotImplemented` to fallback to the traditional behavior.

Якщо визначено і `dispatch_table`, і `reducer_override()`, то метод `reducer_override()` має пріоритет.

Примітка

З міркувань продуктивності `reducer_override()` не можна викликати для таких об’єктів: `None`, `True`, `False` і точних екземплярів `int` , `float`, `bytes`, `str`, `dict`, `set`, `frozenset`, `list` і `tuple`.

Ось простий приклад, де ми дозволяємо маринувати та реконструювати заданий клас:

    import io
    import pickle

    class MyClass:
        my_attribute = 1

    class MyPickler(pickle.Pickler):
        def reducer_override(self, obj):
            """Custom reducer for MyClass."""
            if getattr(obj, "__name__", None) == "MyClass":
                return type, (obj.__name__, obj.__bases__,
                              {'my_attribute': obj.my_attribute})
            else:
                # For any other object, fallback to usual reduction
                return NotImplemented

    f = io.BytesIO()
    p = MyPickler(f)
    p.dump(MyClass)

    del MyClass

    unpickled_class = pickle.loads(f.getvalue())

    assert isinstance(unpickled_class, type)
    assert unpickled_class.__name__ == "MyClass"
    assert unpickled_class.my_attribute == 1

## Позасмугові буфери

Added in version 3.8.

У деяких контекстах модуль `pickle` використовується для передачі величезних обсягів даних. Тому може бути важливо мінімізувати кількість копій пам’яті, щоб зберегти продуктивність і споживання ресурсів. Однак нормальна робота модуля `pickle`, оскільки він перетворює графоподібну структуру об’єктів у послідовний потік байтів, за своєю суттю передбачає копіювання даних до потоку pickle і з нього.

Це обмеження можна уникнути, якщо і провайдер (реалізація типів об’єктів, що передаються), і споживач (реалізація системи зв’язку) підтримують засоби позасмугової передачі, надані протоколом pickle 5 і вище.

### API провайдера

The large data objects to be pickled must implement a `__reduce_ex__()` method specialized for protocol 5 and higher, which returns a `PickleBuffer` instance (instead of e.g. a `bytes` object) for any large data.

Об’єкт `PickleBuffer` сигналізує, що базовий буфер придатний для позасмугової передачі даних. Ці об’єкти залишаються сумісними зі звичайним використанням модуля `pickle`. Однак споживачі також можуть повідомити `pickle`, що вони самостійно оброблятимуть ці буфери.

### Споживацький API

Система зв’язку може ввімкнути спеціальну обробку об’єктів `PickleBuffer`, створених під час серіалізації графа об’єктів.

На стороні надсилання йому потрібно передати аргумент buffer_callback до `Pickler` (або до функції `dump()` або `dumps()`), який буде викликано з кожним `PickleBuffer`, створений під час маринування графа об’єкта. Буфери, накопичені buffer_callback, не бачитимуть своїх даних, скопійованих у потік pickle, буде вставлено лише дешевий маркер.

На стороні приймача йому потрібно передати аргумент buffers до `Unpickler` (або до функції `load()` або `loads()`), який є ітерацією буферів, які були передається до buffer_callback. Ця ітерація повинна створювати буфери в тому ж порядку, в якому вони були передані buffer_callback. Ці буфери нададуть дані, очікувані реконструкторами об’єктів, маринування яких створило оригінальні об’єкти `PickleBuffer`.

Між відправною та приймальною сторонами система зв’язку може вільно реалізувати власний механізм передачі для позасмугових буферів. Потенційна оптимізація включає використання спільної пам’яті або залежне від типу даних стиснення.

### приклад

Ось тривіальний приклад, у якому ми реалізуємо підклас `bytearray`, здатний брати участь у позаполосному відбиранні буфера:

    class ZeroCopyByteArray(bytearray):

        def __reduce_ex__(self, protocol):
            if protocol >= 5:
                return type(self)._reconstruct, (PickleBuffer(self),), None
            else:
                # PickleBuffer is forbidden with pickle protocols <= 4.
                return type(self)._reconstruct, (bytearray(self),)

        @classmethod
        def _reconstruct(cls, obj):
            with memoryview(obj) as m:
                # Get a handle over the original buffer object
                obj = m.obj
                if type(obj) is cls:
                    # Original buffer object is a ZeroCopyByteArray, return it
                    # as-is.
                    return obj
                else:
                    return cls(obj)

Реконструктор (метод класу `_reconstruct`) повертає наданий об’єкт буфера, якщо він має правильний тип. Це простий спосіб імітувати поведінку без копіювання на цьому прикладі іграшки.

Зі сторони споживача ми можемо відібрати ці об’єкти звичайним способом, який після десеріалізації дасть нам копію оригінального об’єкта:

    b = ZeroCopyByteArray(b"abc")
    data = pickle.dumps(b, protocol=5)
    new_b = pickle.loads(data)
    print(b == new_b)  # True
    print(b is new_b)  # False: a copy was made

Але якщо ми передаємо buffer_callback, а потім повертаємо накопичені буфери під час десеріалізації, ми можемо повернути вихідний об’єкт:

    b = ZeroCopyByteArray(b"abc")
    buffers = []
    data = pickle.dumps(b, protocol=5, buffer_callback=buffers.append)
    new_b = pickle.loads(data, buffers=buffers)
    print(b == new_b)  # True
    print(b is new_b)  # True: no copy was made

Цей приклад обмежений тим фактом, що `bytearray` виділяє власну пам’ять: ви не можете створити екземпляр `bytearray`, який підтримується пам’яттю іншого об’єкта. Однак сторонні типи даних, такі як масиви NumPy, не мають цього обмеження та дозволяють використовувати нульове копіювання (або створення якомога меншої кількості копій) під час передачі між окремими процесами чи системами.

Дивись також

PEP 574 – Протокол Pickle 5 із позаполосними даними

## Обмеження Globals

За замовчуванням unpickling імпортує будь-який клас або функцію, знайдені в даних pickle. Для багатьох програм така поведінка є неприйнятною, оскільки вона дозволяє unpickler імпортувати та викликати довільний код. Просто подумайте, що робить цей створений вручну потік даних маринованих огірків під час завантаження:

    >>> import pickle
    >>> pickle.loads(b"cos\nsystem\n(S'echo hello world'\ntR.")
    hello world
    0

У цьому прикладі unpickler імпортує функцію `os.system()`, а потім застосовує рядковий аргумент «echo hello world». Хоча цей приклад не образливий, неважко уявити такий, який може пошкодити вашу систему.

З цієї причини ви можете контролювати те, що буде видалено, налаштувавши `Unpickler.find_class()`. На відміну від назви, `Unpickler.find_class()` викликається щоразу, коли запитується глобал (тобто клас або функція). Таким чином, можна або повністю заборонити глобальні елементи, або обмежити їх безпечною підмножиною.

Ось приклад unpickler, який дозволяє завантажити лише декілька безпечних класів із модуля `builtins`:

    import builtins
    import io
    import pickle

    safe_builtins = {
        'range',
        'complex',
        'set',
        'frozenset',
        'slice',
    }

    class RestrictedUnpickler(pickle.Unpickler):

        def find_class(self, module, name):
            # Only allow safe classes from builtins.
            if module == "builtins" and name in safe_builtins:
                return getattr(builtins, name)
            # Forbid everything else.
            raise pickle.UnpicklingError("global '%s.%s' is forbidden" %
                                         (module, name))

    def restricted_loads(s):
        """Helper function analogous to pickle.loads()."""
        return RestrictedUnpickler(io.BytesIO(s)).load()

Зразок використання нашого unpickler, що працює за призначенням:

    >>> restricted_loads(pickle.dumps([1, 2, range(15)]))
    [1, 2, range(0, 15)]
    >>> restricted_loads(b"cos\nsystem\n(S'echo hello world'\ntR.")
    Traceback (most recent call last):
      ...
    pickle.UnpicklingError: global 'os.system' is forbidden
    >>> restricted_loads(b'cbuiltins\neval\n'
    ...                  b'(S\'getattr(__import__("os"), "system")'
    ...                  b'("echo hello world")\'\ntR.')
    Traceback (most recent call last):
      ...
    pickle.UnpicklingError: global 'builtins.eval' is forbidden

Як показують наші приклади, ви повинні бути обережними з тим, що ви дозволяєте не маринувати. Тому, якщо питання безпеки викликає занепокоєння, ви можете розглянути такі альтернативи, як маршалінговий API у `xmlrpc.client` або рішення сторонніх розробників.

## Продуктивність

Останні версії протоколу pickle (від протоколу 2 і вище) містять ефективне двійкове кодування для кількох загальних функцій і вбудованих типів. Крім того, модуль `pickle` має прозорий оптимізатор, написаний мовою C.

## Приклади

Для найпростішого коду використовуйте функції `dump()` і `load()`.

    import pickle

    # An arbitrary collection of objects supported by pickle.
    data = {
        'a': [1, 2.0, 3+4j],
        'b': ("character string", b"byte string"),
        'c': {None, True, False}
    }

    with open('data.pickle', 'wb') as f:
        # Pickle the 'data' dictionary using the highest protocol available.
        pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)

У наступному прикладі зчитуються результуючі мариновані дані.

    import pickle

    with open('data.pickle', 'rb') as f:
        # The protocol version used is detected automatically, so we do not
        # have to specify it.
        data = pickle.load(f)

## Command-line interface

The `pickle` module can be invoked as a script from the command line, it will display contents of the pickle files. However, when the pickle file that you want to examine comes from an untrusted source, `-m pickletools` is a safer option because it does not execute pickle bytecode, see pickletools CLI usage.

    python -m pickle pickle_file [pickle_file ...]

The following option is accepted:

pickle_file

  A pickle file to read, or `-` to indicate reading from standard input.

Дивись також

Модуль `copyreg`

  Реєстрація конструктора інтерфейсу Pickle для типів розширень.

Модуль `pickletools`

  Інструменти для роботи з маринованими даними та їх аналізу.

Модуль `shelve`

  Індексовані бази даних об’єктів; використовує `pickle`.

Модуль `copy`

  Неглибоке і глибоке копіювання об’єктів.

Модуль `marshal`

  Високопродуктивна серіалізація вбудованих типів.

Виноски

[ 1 ]

Не плутайте це з модулем `marshal`

[ 2 ]

Ось чому функції `lambda` не можна маринувати: усі функції `lambda` мають однакову назву: `<lambda>`.

[ 3 ]

Виняток, імовірно, буде `ImportError` або `AttributeError`, але це може бути щось інше.

[ 4 ]

Модуль `copy` використовує цей протокол для дрібних і глибоких операцій копіювання.

[ 5 ]

Обмеження щодо буквено-цифрових символів пов’язане з тим, що постійні ідентифікатори в протоколі 0 відокремлюються символом нового рядка. Тому, якщо в постійних ідентифікаторах зустрічаються будь-які символи нового рядка, результуючі мариновані дані стануть нечитабельними.