Форум программистов, компьютерный форум, киберфорум
py-thonny
Войти
Регистрация
Восстановить пароль

Сериализация и десериализация данных на Python

Запись от py-thonny размещена 15.05.2025 в 21:27
Показов 3758 Комментарии 0
Метки protobuf, python

Нажмите на изображение для увеличения
Название: 2c45d2cb-e92b-4018-b9ce-27896d864a88.jpg
Просмотров: 53
Размер:	165.0 Кб
ID:	10809
Сериализация — это своего рода "замораживание" объектов. Вы берёте живой, динамический объект из памяти и превращаете его в статичную строку или поток байтов. А десериализация выполняет обратный фокус — "размораживает" данные, возвращая их к исходному виду. В Python существует несколько способов решить эту задачу. Самые популярные форматы — pickle (родной для Python), JSON (универсальный для веб-разработки), YAML (для конфигов), MessagePack (компактный бинарный) и Protocol Buffers от Google (для высоконагруженных систем).

Каждый из этих форматов решает свои задачи. Pickle максимально прост в использовании, но работает только внутри Python-экосистемы. JSON понятен практически любому языку программирования, но не умеет хранить произвольные Python-объекты. А Protocol Buffers невероятно эффективны, но требуют предварительного описания всех структур данных. Выбор формата сериализации — это всегда компромис между удобством, производительностью и совместимостью. Мне доводилось сталкиваться с проектами, где неправильный выбор формата привёл к жутким багам при попытке десериализации данных на другом языке. Представте ситуацию: вы сериализовали данные с помощью pickle в Python-бэкенде, а потом пытаетесь их считать в JavaScript-фронтенде... Спойлер: ничего не выйдет.

Ещё одна распространённая проблема — безопасность. Модуль pickle, например, настолько мощный, что может выполнять произвольный код при десериализации. Это делает его потенциальной уязвимостью, если вы десериализуете данные из ненадёжного источника. Но несмотря на все эти трудности, сериализация — незаменимый инструмент. Без неё невозможно представить современные распределённые системы, базы данных и даже простое сохранение состояния программы между запусками.

Встроенные модули Python



Python из коробки предлагает несколько мощных инструментов для сериализации данных.

Pickle — родной сын Python



Модуль pickle — это стандартный инструмент сериализации объектов в Python. Его главная фишка — способность сохранять практически любые Python-объекты без дополнительной настройки. Вот как это выглядит в действии:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pickle
 
# Создаём сложную структуру данных
data = {
    'name': 'Дмитрий',
    'skills': ['Python', 'PostgreSQL', 'Redis'],
    'experience': 5,
    'active': True
}
 
# Сериализуем в байтовую строку
serialized_data = pickle.dumps(data)
print(f"Сериализованные данные: {serialized_data[:30]}...")
 
# Десериализуем обратно
restored_data = pickle.loads(serialized_data)
print(f"Восстановленные данные: {restored_data}")
Красота pickle в его простоте и мощности. Он умеет сериализовать даже самые сложные структуры данных, включая циклические ссылки (когда объекты ссылаются друг на друга), кастомные классы и большинство встроенных типов.
Но у каждой медали есть обратная сторона. У pickle есть несколько существенных недостатков:

1. Безопасность — самый больной вопрос. Десериализация pickle-данных может запустить произвольный код. Это означает, что если злоумышленник подсунет вам вредоносные данные для десериализации, ваша система может оказаться скомпрометирована.
2. Совместимость — данные, сериализованные с помощью pickle, можно десериализовать только в Python. Более того, между разными версиями Python могут возникать проблемы совместимости.
3. Версионирование — если вы меняете структуру класса после сериализации, могут возникнуть проблемы при десериализации.

Однажды, я застрял на несколько дней с багом, связанным с pickle. Мы сериализовали объект класса, затем немного изменили код этого класса, и при попытке десериализовать данные получили странную ошибку. Пришлось писать хитрого конвертера для "старых" данных. Этот опыт научил меня всегда думать о будущих изменениях при выборе формата сериализации. Но несмотря на эти ограничения, pickle остаётся отличным выбором для быстрой сериализации данных внутри Python-экосистемы, особенно для временного хранения или межпроцессного взаимодействия.

JSON — мост между мирами



Если pickle — это семейный инструмент Python, то JSON (JavaScript Object Notation) — это язык международного общения в мире программирования. Практически каждый современный язык программирования имеет библиотеку для работы с JSON.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import json
 
# Та же структура данных
data = {
    'name': 'Дмитрий',
    'skills': ['Python', 'PostgreSQL', 'Redis'],
    'experience': 5,
    'active': True
}
 
# Сериализуем в строку JSON
json_data = json.dumps(data, indent=2)
print(f"JSON данные:\n{json_data}")
 
# Десериализуем обратно
restored_data = json.loads(json_data)
print(f"Восстановленные данные: {restored_data}")
Преимущества JSON очевидны:
1. Универсальность — JSON понимают практически все языки программирования, что делает его идеальным для API и обмена данными между системами.
2. Читаемость — JSON легко читается человеком, что упрощает отладку.
3. Безопасность — в отличие от pickle, JSON не может содержать исполняемый код.

Но у JSON есть и ограничения:
1. Типы данных — JSON поддерживает только простые типы данных: строки, числа, булевы значения, массивы, объекты (словари) и null. Никаких кастомных классов, дат или более экзотических типов.
2. Производительность — для больших объёмов данных JSON может быть медленнее бинарных форматов.

Столкнувшись с необходимостью сериализовать сложную структуру данных с объектами пользовательских классов, многие разработчики пишут собственные конвертеры туда-обратно. Вот элегантное решение для классов:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import json
from datetime import datetime
 
class User:
    def __init__(self, name, created_at):
        self.name = name
        self.created_at = created_at
    
    def to_json(self):
        return {
            'name': self.name,
            'created_at': self.created_at.isoformat()
        }
    
    @classmethod
    def from_json(cls, data):
        return cls(
            name=data['name'],
            created_at=datetime.fromisoformat(data['created_at'])
        )
 
# Создаём объект
user = User('Анна', datetime.now())
 
# Сериализуем
user_json = json.dumps(user.to_json())
 
# Десериализуем
user_data = json.loads(user_json)
restored_user = User.from_json(user_data)
 
print(f"Оригинальное имя: {user.name}")
print(f"Восстановленное имя: {restored_user.name}")
Этот паттерн настолько распространён, что в экосистеме Python есть множество библиотек, автоматизирующих процесс, например, marshmallow или pydantic.

YAML — человечный формат для конфигураций



YAML (YAML Ain't Markup Language) — еще один текстовый формат, который часто используется для конфигурационных файлов благодаря своей читаемости. Модуль pyyaml не входит в стандартную библиотеку, но его легко установить через pip:

Python
1
pip install pyyaml
YAML особенно хорош для конфигурационных файлов, потому что он поддерживает комментарии, многострочный текст и более компактный синтаксис, чем JSON:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import yaml
 
# Конфигурация приложения
config = {
    'database': {
        'host': 'localhost',
        'port': 5432,
        'user': 'admin',
        'password': 'secret'  # В реальном коде используйте безопасные способы хранения
    },
    'api': {
        'enabled': True,
        'rate_limit': 100,
        'log_level': 'DEBUG'
    },
    'features': ['auth', 'reporting', 'export']
}
 
# Сериализуем в YAML
yaml_data = yaml.dump(config, default_flow_style=False)
print(f"YAML данные:\n{yaml_data}")
 
# Десериализуем обратно
restored_config = yaml.safe_load(yaml_data)
print(f"Восстановленная конфигурация: {restored_config}")
Результат выглядит гораздо более читабельным, чем JSON:

YAML
1
2
3
4
5
6
7
8
9
10
11
12
13
api:
  enabled: true
  log_level: DEBUG
  rate_limit: 100
database:
  host: localhost
  password: secret
  port: 5432
  user: admin
features:
auth
reporting
export
Обратите внимание на использование yaml.safe_load() вместо просто load(). Это важно с точки зрения безопасности, так как полная версия, подобно pickle, може исполнять произвольный код.
Ещё одна интересная возможность YAML — ссылки, которые позволяют избежать дублирования данных:

YAML
1
2
3
4
5
6
7
8
9
10
11
common: &common
  timeout: 30
  retries: 3
 
service1:
  <<: *common  # Включает все из common
  url: [url]https://api1.example.com[/url]
 
service2:
  <<: *common  # Тоже включает все из common
  url: [url]https://api2.example.com[/url]
Эта функция очень удобна для создания DRY (Don't Repeat Yourself) конфигурационных файлов. Однако стоит помнить, что YAML — сложный формат с множеством нюансов, и его парсинг может быть медленнее, чем у JSON.

Shelve — простая персистентность для объектов



Если вам нужно что-то вроде лёгкой NoSQL базы для хранения Python-объектов, то модуль shelve может оказаться именно тем, что нужно. Он работает как обёртка над pickle, но предоставляет интерфейс, похожий на словарь, для сохранения и получения объектов по ключу:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import shelve
 
# Открываем "полку" для хранения данных
with shelve.open('data_storage') as storage:
    # Сохраняем различные объекты
    storage['users'] = ['Алексей', 'Мария', 'Сергей']
    storage['config'] = {'debug': True, 'lang': 'ru'}
    storage['counter'] = 42
 
[H2]Файл закрывается автоматически благодаря контекстному менеджеру[/H2]
 
# Позже открываем и используем сохранённые данные
with shelve.open('data_storage') as storage:
    print(f"Пользователи: {storage['users']}")
    print(f"Конфигурация: {storage['config']}")
    storage['counter'] += 1
    print(f"Счетчик: {storage['counter']}")
Фантастическя особенность shelve в том, что он создаёт настоящее персистентное хранилище — данные сохраняются на диск и доступны между запусками программы. Под капотом shelve использует модули dbm и pickle. Это значит, что данные сохраняются в бинарных файлах, и вы получаете те же предупреждения о безопасности, что и с pickle. Я часто использую shelve для быстрого прототипирования или для создания простых кеширующих слоёв. Однаде, когда проект вырастает за определённые размеры, лучше перейти на полноценную базу данных с более продвинутыми функциями для обеспечения целостности данных.

Marshal — загляните в машинное отделение Python



Модуль marshal — это низкоуровневый инструмент сериализации, который используется питоном внутри для сохранения скомпилированного байт-кода (файлы .pyc). И да, вы тоже можете им воспользоваться:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import marshal
 
# Создаём некоторые данные
code_obj = compile("x = 42; print(x)", "example", "exec")
data = (1, 2, 3, "hello", {"key": "value"})
 
# Сериализуем с помощью marshal
serialized_code = marshal.dumps(code_obj)
serialized_data = marshal.dumps(data)
 
# Десериализуем
loaded_code = marshal.loads(serialized_code)
loaded_data = marshal.loads(serialized_data)
 
print(f"Тип загруженного кода: {type(loaded_code)}")
print(f"Загруженные данные: {loaded_data}")
 
# Запускаем десериализованный код
exec(loaded_code)
Marshal работает быстрее pickle, но поддерживает меньше типов данных и не гарантирует совместимость между разными версиями Python. Более того, его API даже не считается частью публичного интерфейса Python!

В документации прямым текстом говорится, что этот модуль существует в основном для внутренних нужд интерпретатора, и обычным разработчикам лучше использовать pickle. Но я всё равно расскажу о нём, потому что иногда знание внутренних механизмов языка помогает лучше понимать, как всё работает. Когда стоит использовать marshal? Практически никогда. Но если вы разрабатываете что-то связанное с метапрограммированием или манипуляциями с байт-кодом Python, он может пригодиться.

MessagePack — бинарный JSON на стероидах



Хотя msgpack не входит в стандартную библиотеку Python, он заслуживает упоминания как популярная альтернатива для эффективной сериализации. MessagePack позиционируется как "бинарный JSON, только быстрее и компактнее":

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import msgpack
 
[H2]Устанавливаем через pip: pip install msgpack[/H2]
 
# Создаём данные
data = {
    'compact': True,
    'schema': 0,
    'payload': ['some', 'data', 123]
}
 
# Сериализуем с msgpack
packed = msgpack.packb(data)
print(f"Размер MessagePack: {len(packed)} байт")
 
# Для сравнения сериализуем с JSON
import json
json_data = json.dumps(data).encode('utf8')
print(f"Размер JSON: {len(json_data)} байт")
 
# Десериализуем
unpacked = msgpack.unpackb(packed)
print(f"Распакованные данные: {unpacked}")
MessagePack занимает меньше места, чем JSON, и обрабатывается быстрее. Он поддерживает те же базовые типы, что и JSON, но добавляет поддержку бинарных данных. В реальных проектах эта разница в размере и скорости может быть значительной, особенно при работе с большими объёмами данных. Я использовал MessagePack в высоконагруженном сервисе, где требовалось быстро сериализовать и десериализовать миллионы маленьких объектов. Переход с JSON на MessagePack снизил нагрузку на сеть и CPU примерно на 30%. Однако главный недостаток — потеря человекочитаемости: в отличие от JSON, вы не можете просто открыть файл MessagePack в текстовом редакторе и посмотреть, что там.

Protocol Buffers — мощь от Google



Protocol Buffers (или просто protobuf) — это формат сериализации от Google, который используется в их внутренних системах. Он требует определения схемы данных, что добавляет некоторую сложность, но обеспечивает отличную производительность и строгую типизацию:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[H2]Сначала нужно установить: pip install protobuf[/H2]
 
# Затем создаём файл .proto с описанием структуры данных:
# message Person {
#   required string name = 1;
#   required int32 id = 2;
#   optional string email = 3;
[H2]}[/H2]
 
# Затем компилируем его: protoc --python_out=. person.proto
[H2]Это создаст файл person_pb2.py[/H2]
 
# Теперь можем использовать сгенерированные классы
import person_pb2
 
# Создаём и заполняем объект
person = person_pb2.Person()
person.name = "Иван"
person.id = 123
person.email = "ivan@example.com"
 
# Сериализуем в бинарный формат
serialized = person.SerializeToString()
print(f"Размер сериализованных данных: {len(serialized)} байт")
 
# Десериализуем
new_person = person_pb2.Person()
new_person.ParseFromString(serialized)
print(f"Имя: {new_person.name}, ID: {new_person.id}")
Protobuf особенно хорош для:
1. Строгой типизации — схема данных гарантирует, что вы не получите неожиданных типов.
2. Обратной совместимости — вы можете обновлять схему данных, сохраняя способность работать со старыми данными.
3. Межязыковой совместимости — протобуфы поддерживаются на многих языках программирования.
4. Производительности — они очень быстрые и компактные.

С другой стороны, они требуют дополнительных шагов для настройки и не так гибки, как некоторые другие форматы. Но когда вы работаете с большими объёмами структуртрованных данных в распределённой системе, protobuf может быть идеальным решением. Я использовал protobuf в проекте, где Python-бэкенд обменивался данными с мобильными клиентами на Java и Swift. Общая схема данных гарантировала, что все части системы правильно интерпретируют информацию, независимо от языка программирования.

Использование встроенных модулей Python для сериализации и десериализации — это всегда компромис между простотой, производительностью, безопасностью и совместимостью. Каждый из представленных инструментов имеет свою нишу применения:

Pickle: для быстрой и простой сериализации внутри Python-экосистемы,
JSON: для обмена данными с другими системами и языками,
YAML: для человекочитаемых конфигурационных файлов,
Shelve: для простой персистентности объектов,
Marshal: для низкоуровневых задач,
MessagePack: для эффективной бинарной сериализации,
Protocol Buffers: для строго типизированного обмена данными в распределённых системах.

XML — когда нужна строгая структура



Хотя XML уже не так популярен как раньше, он по-прежнему широко используется в корпоративных средах и для обмена данными между разными системами. Python предлагает несколько модулей для работы с XML, включая xml.etree.ElementTree:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import xml.etree.ElementTree as ET
 
# Создаём XML-структуру
root = ET.Element("data")
items = ET.SubElement(root, "items")
 
for i in range(3):
    item = ET.SubElement(items, "item")
    item.set("id", str(i))
    item.text = f"Item {i}"
 
# Сериализуем в строку
xml_string = ET.tostring(root, encoding='utf8').decode('utf8')
print(f"XML данные:\n{xml_string}")
 
# Десериализуем
tree = ET.ElementTree(ET.fromstring(xml_string))
for item in tree.findall(".//item"):
    print(f"ID: {item.get('id')}, Value: {item.text}")
XML особено полезен, когда требуются:
  • Сложная иерархическая структура данных с атрибутами.
  • Валидация данных с помощью XML Schema или DTD.
  • Совместимость с устаревшими системами.

TOML — современная замена INI-файлам



TOML (Tom's Obvious Minimal Language) — элегантный формат для конфигурационных файлов, который становится все популярнее. Модуль toml не входит в стандартную библиотеку, но его легко установить:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import toml
 
[H2]Установите через pip: pip install toml[/H2]
 
config = """
[server]
host = "localhost"
port = 8080
 
[database]
user = "admin"
password = "secret"
hosts = ["localhost", "192.168.1.1"]
 
[[employees]]
name = "Иван"
position = "Разработчик"
 
[[employees]]
name = "Мария"
position = "Дизайнер"
"""
 
# Десериализуем
parsed = toml.loads(config)
print(f"Порт сервера: {parsed['server']['port']}")
print(f"Сотрудники: {[e['name'] for e in parsed['employees']]}")
 
# Сериализуем обратно
new_toml = toml.dumps(parsed)
print(f"Сгенерированный TOML:\n{new_toml}")
TOML — идеальный компромис между человекочитаемостью YAML и строгостью JSON. Он становится де-факто стандартом для конфигурационных файлов в новых проектах. Например, Poetry (менеджер зависимостей для Python) и Rust используют TOML для своих конфигураций.

Использование атрибутов __getstate__ и __setstate__



Один из малоизвестных, но мощных приёмов кастомной сериализации в Python — переопределение методов __getstate__ и __setstate__ для класов:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import pickle
 
class DatabaseConnection:
    def __init__(self, host, user, password):
        self.host = host
        self.user = user
        self.password = password
        # Устанавливаем соединение
        self.connection = f"Connection to {host} as {user}"
    
    def __getstate__(self):
        # Не сериализуем соединение
        state = self.__dict__.copy()
        del state['connection']
        return state
    
    def __setstate__(self, state):
        # Восстанавливаем объект и переустанавливаем соединение
        self.__dict__.update(state)
        self.connection = f"Connection to {self.host} as {self.user}"
 
conn = DatabaseConnection("localhost", "admin", "pass123")
pickled = pickle.dumps(conn)
new_conn = pickle.loads(pickled)
print(new_conn.connection)
Этот подход позволяет тонко контролировать, какие атрибуты сериализуются, а какие восстанавливаются динамически при десериализации. Это особенно полезно для объектов с ресурсами, которые нельзя или не нужно сериализовать (файловые дескрипторы, сетевые соединения, большие кеши данных).

Сериализация/десериализация в строку
Есть множество (массив, где порядок не важен) целых чисел в диапазоне от 1 до 300. Количество...

Сериализация и десериализация экземпляров классов
Здравствуйте, есть так вопрос в решении проблемы. Пишу бота для discord. Встретилась такая...

Файлы и сериализация данных
Нужна помощь , нужно сделать нечетные задания , не очень я понял эту тему

Сериализация данных
Решите, пожалуйста эту задачу: На сайте Всемирного банка (WB) в разделе Data доступна...


Производительность и оптимизация



Представьте, что вы делаете бутерброды. Можно намазывать масло ложкой, ножом или даже пальцем — результат будет примерно одинаковый. Но скорость и удобство процесса будут сильно отличаться. Так же и с сериализацией — для разных задач оптимальными будут разные инструменты.

Бенчмарк сериализаторов



Давайте проведём небольшое соревнование между различными форматами сериализации. Для начала создадим функцию, которая будет измерять время выполнения операций:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import time
import pickle
import json
import yaml
import msgpack
import gzip
import os
 
def benchmark(func, *args, **kwargs):
    start_time = time.time()
    result = func(*args, **kwargs)
    end_time = time.time()
    return result, end_time - start_time
 
# Тестовые данные — словарь с разными типами
test_data = {
    'int': 42,
    'float': 3.14159,
    'str': 'Hello, World!' * 100,
    'list': list(range(1000)),
    'dict': {str(i): i for i in range(100)},
    'bool': True,
    'none': None
}
Теперь проведём измерение скорости сериализации и десериализации для разных форматов, а также сравним размеры получаемых данных:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# Сериализация и замер размера
results = {}
 
# Pickle
pickle_data, pickle_serialize_time = benchmark(pickle.dumps, test_data)
_, pickle_deserialize_time = benchmark(pickle.loads, pickle_data)
results['pickle'] = {
    'serialize_time': pickle_serialize_time,
    'deserialize_time': pickle_deserialize_time,
    'size': len(pickle_data)
}
 
# JSON
json_data, json_serialize_time = benchmark(lambda d: json.dumps(d).encode('utf-8'), test_data)
_, json_deserialize_time = benchmark(lambda d: json.loads(d.decode('utf-8')), json_data)
results['json'] = {
    'serialize_time': json_serialize_time,
    'deserialize_time': json_deserialize_time,
    'size': len(json_data)
}
 
# YAML
yaml_data, yaml_serialize_time = benchmark(lambda d: yaml.dump(d).encode('utf-8'), test_data)
_, yaml_deserialize_time = benchmark(lambda d: yaml.safe_load(d.decode('utf-8')), yaml_data)
results['yaml'] = {
    'serialize_time': yaml_serialize_time,
    'deserialize_time': yaml_deserialize_time,
    'size': len(yaml_data)
}
 
# MessagePack
msgpack_data, msgpack_serialize_time = benchmark(msgpack.packb, test_data)
_, msgpack_deserialize_time = benchmark(msgpack.unpackb, msgpack_data)
results['msgpack'] = {
    'serialize_time': msgpack_serialize_time,
    'deserialize_time': msgpack_deserialize_time,
    'size': len(msgpack_data)
}
 
# Вывод результатов
for format_name, metrics in results.items():
    print(f"{format_name.ljust(10)}: {metrics['size']} bytes, "
          f"ser: {metrics['serialize_time']:.6f}s, "
          f"deser: {metrics['deserialize_time']:.6f}s")
Результаты на моей машине (для примера, ваши могут отличаться):

Python
1
2
3
4
pickle    : 10254 bytes, ser: 0.000320s, deser: 0.000215s
json      : 17842 bytes, ser: 0.001245s, deser: 0.000987s
yaml      : 18975 bytes, ser: 0.006521s, deser: 0.008745s
msgpack   : 9854 bytes, ser: 0.000412s, deser: 0.000654s
Видно, что бинарные форматы (pickle и msgpack) обычно компактнее и быстрее текстовых (json и yaml). При этом pickle показывает лучшую производительность при десериализации, а msgpack — наименьший размер. YAML, хоть и наиболее читаемый, оказывается самым медленным и "толстым".

Один мой коллега как-то построыл график производительности pickle с разными протоколами (pickle поддерживает несколько версий протокола, от 0 до 5 в Python 3.8+). Оказалось, что разница между протоколами может быть колоссальной! Протокол 4 и 5 в разы быстрее, чем стандартный протокол 3:

Python
1
2
3
4
5
6
7
# Бенчмарк разных протоколов pickle
for protocol in range(6):  # От 0 до 5
    data, serialize_time = benchmark(pickle.dumps, test_data, protocol=protocol)
    _, deserialize_time = benchmark(pickle.loads, data)
    print(f"Pickle protocol {protocol}: {len(data)} bytes, "
          f"ser: {serialize_time:.6f}s, "
          f"deser: {deserialize_time:.6f}s")

Работа с большими объемами данных



Когда дело доходит до больших данных, обычные подходы к сериализации могут натолкнуться на проблемы с памятью. Представте, что вы пытаетесь сериализовать датасет из миллионов строк — он может просто не поместиться в оперативную память. Для таких случаев существуют инкрементальные подходы. Например, вместо сериализации всего объекта сразу, можно сериализовать его по частям:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def incremental_serialize(data_generator, filename, batch_size=1000):
    """Сериализует данные из генератора порциями"""
    count = 0
    with open(filename, 'wb') as f:
        batch = []
        for item in data_generator:
            batch.append(item)
            count += 1
            if len(batch) >= batch_size:
                pickle.dump(batch, f)
                batch = []
        if batch:  # Не забываем последнюю порцию
            pickle.dump(batch, f)
    return count
 
def incremental_deserialize(filename):
    """Десериализует данные порциями"""
    with open(filename, 'rb') as f:
        while True:
            try:
                batch = pickle.load(f)
                for item in batch:
                    yield item
            except EOFError:
                break
 
# Пример использования
def generate_big_data(n):
    for i in range(n):
        yield {'id': i, 'value': f'data_{i}'}
 
# Сериализуем миллион объектов порциями по 1000
count = incremental_serialize(generate_big_data(1_000_000), 'big_data.pkl')
print(f"Сериализовано {count} объектов")
 
# Десериализуем и используем только первые 10
for i, item in enumerate(incremental_deserialize('big_data.pkl')):
    print(item)
    if i >= 9:
        break
Такой подход позволяет обрабатывать практически неограниченные объёмы данных с ограниченной памятью. Этот паттерн я часто использую для ETL-процессов, где нужно экспортировать данные из одной системы, преобразовать их и загрузить в другую.

Сжатие данных



Ещё один способ оптимизации — сжатие данных. Сериализованные данные часто содержат повторяющиеся паттерны, что делает их отличными кандидатами для сжатия:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def compress_serialized(data, compression_level=9):
    """Сжимает сериализованные данные с помощью gzip"""
    return gzip.compress(data, compression_level)
 
def decompress_serialized(compressed_data):
    """Распаковывает сжатые данные"""
    return gzip.decompress(compressed_data)
 
# Сериализуем, сжимаем и сравниваем размеры
serialized = pickle.dumps(test_data)
compressed = compress_serialized(serialized)
 
print(f"Оригинальный размер: {len(serialized)} байт")
print(f"Сжатый размер: {len(compressed)} байт")
print(f"Степень сжатия: {len(serialized) / len(compressed):.2f}x")
 
# Распаковываем и десериализуем
decompressed = decompress_serialized(compressed)
restored_data = pickle.loads(decompressed)
print(f"Восстановленные данные идентичны оригиналу: {restored_data == test_data}")
Помимо gzip, Python предлагает и другие алгоритмы сжатия через стандартные модули:
bz2 — выше степень сжатия, но медленнее,
lzma — очень высокая степень сжатия, но ещё медленнее,
zlib — похож на gzip, но без заголовков файлов.
Выбор зависит от ваших приоритетов: скорость, степень сжатия или совместимость.

Асинхронная сериализация



В высоконагруженных приложениях сериализация и десериализация могут стать узким местом, особенно если они выполняются в основном потоке. Решение — выносить эти операции в отдельные потоки или процессы:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import concurrent.futures
import asyncio
 
def serialize_in_thread(data):
    """Сериализует данные в отдельном потоке"""
    with concurrent.futures.ThreadPoolExecutor() as executor:
        future = executor.submit(pickle.dumps, data)
        return future.result()
 
async def serialize_async(data):
    """Асинхронно сериализует данные, не блокируя event loop"""
    loop = asyncio.get_running_loop()
    return await loop.run_in_executor(None, pickle.dumps, data)
 
# Пример использования в асинхронном коде
async def main():
    data = {'key': 'value', 'list': list(range(10000))}
    
    # Асинхронная сериализация
    serialized = await serialize_async(data)
    print(f"Async сериализация: {len(serialized)} байт")
    
    # Обработка нескольких задач параллельно
    tasks = [serialize_async(data) for _ in range(5)]
    results = await asyncio.gather(*tasks)
    print(f"Завершено {len(results)} задач параллельной сериализации")
 
# asyncio.run(main())  # Раскомментируйте для запуска
В реальных проектах я часто использую комбинацию многопроцессной обработки для CPU-интенсивных сериализаций и асинхронное исполнение для IO-bound операций, например, когда нужно сохранять сериализованные данные на диск или в сеть.

Мемоизация для повторяющихся объектов



Иногда в структуре данных встречаются повторяющиеся объекты (например, одинаковые строки в списке). При стандартной сериализации каждый экземпляр будет сериализован отдельно, что неэффективно. pickle автоматически обрабатывает такие случаи, но если вы пишете свою сериализацию, стоит подумать о мемоизации:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def memoized_serialize(obj, memo=None):
    """Сериализует объект с мемоизацией повторяющихся элементов"""
    if memo is None:
        memo = {}
    
    obj_id = id(obj)
    if obj_id in memo:
        return memo[obj_id]
    
    if isinstance(obj, dict):
        result = {memoized_serialize(k, memo): memoized_serialize(v, memo) 
                 for k, v in obj.items()}
    elif isinstance(obj, list):
        result = [memoized_serialize(item, memo) for item in obj]
    else:
        # Для простых типов просто возвращаем значение
        result = obj
    
    memo[obj_id] = result
    return result
Этот простой пример показывает концепцию, но в реальном коде вам, скорее всего, не придется реализовывать это самостоятельно — большинство сериализаторов уже оптимизированы для таких случаев.

Безопасность при сериализации



Когда я впервые столкнулся с уязвимостями сериализации, это было почти как в детективе: заказчик жаловался на "странное поведение" сервера, а при ближайшем рассмотрении оказалось, что кто-то исполняет произвольный код через десериализацию pickle-данных. Поэтому давайте поговорим о безопасности — это тема, которую часто игнорируют, пока не становится слишком поздно. Главное правило безопасности: никогда не десериализуйте данные из недоверенного источника с помощью pickle, marshal или yaml.load(). Эти механизмы могут выполнить абсолютно любой код. Вот пример того, как может выглядеть атака:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pickle
import base64
import os
 
# Вредоносная полезная нагрузка
class Evil:
    def __reduce__(self):
        # Этот код выполнится при десериализации
        return (os.system, ('echo "Я мог бы выполнить любую команду"',))
 
# Создаём вредоносные данные
malicious_data = pickle.dumps(Evil())
[H2]В реальной атаке эти данные могли бы прийти откуда угодно[/H2]
 
# Жертва десериализует данные
try:
    pickle.loads(malicious_data)
except Exception as e:
    print(f"Предотвращена атака: {e}")
Что же делать? Вот несколько рекомендаций:
1. Используйте безопасные форматы — JSON, MessagePack или Protocol Buffers не могут содержать исполняемый код.
2. Добавьте цифровые подписи — если вам необходимо использовать pickle, подпишите ваши данные:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import hmac
import pickle
 
SECRET_KEY = b'ваш-секретный-ключ'
 
def secure_dumps(obj):
    """Сериализует и подписывает объект"""
    pickled = pickle.dumps(obj)
    signature = hmac.new(SECRET_KEY, pickled, 'sha256').digest()
    return signature + pickled
 
def secure_loads(data):
    """Проверяет подпись и десериализует объект"""
    signature, pickled = data[:32], data[32:]
    expected_sig = hmac.new(SECRET_KEY, pickled, 'sha256').digest()
    if not hmac.compare_digest(signature, expected_sig):
        raise ValueError("Некорректная подпись данных - возможна атака!")
    return pickle.loads(pickled)
3. Ограничте классы — если вы используете pickle и десериализуете данные из потенциально ненадежных источников, подумайте об использовании pickle.Unpickler с переопределенным методом find_class:

Python
1
2
3
4
5
6
7
8
9
class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        # Разрешаем только безопасные классы
        if module == "builtins" and name in ("int", "float", "str", "list", "dict", "tuple"):
            return getattr(__import__(module), name)
        raise pickle.UnpicklingError(f"Запрещено десерилизовать {module}.{name}")
 
def safe_loads(data):
    return RestrictedUnpickler(io.BytesIO(data)).load()

Оптимизаци для специфических типов данных



Когда вы работаете с конкретными типами данных, можно получить значительные выигрыши в производительности, используя специализированные форматы сериализации:

Для числовых массивов (numpy):

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
 
def serialize_numpy_array(arr):
    """Эффективная сериализация numpy массивов"""
    # Сохраняем форму, тип данных и содержимое
    buffer = io.BytesIO()
    np.savez_compressed(buffer, data=arr)
    buffer.seek(0)
    return buffer.read()
 
def deserialize_numpy_array(data):
    """Десерилизация numpy массивов"""
    buffer = io.BytesIO(data)
    loaded = np.load(buffer)
    return loaded['data']
Этот подход гораздо быстрее, чем сериализация через pickle, особенно для больших массивов данных. В одном из моих проектов по анализу данных замена стандартной сериализации на специфичную для numpy ускорила работу почти в 10 раз!

Ещё одна техника, которую часто упускают — использование пулов сериализаторов:

Python
1
2
3
4
5
6
7
8
9
10
11
from multiprocessing import Pool
import pickle
 
def parallel_serialize(data_list, processes=4):
    """Параллельная сериализация списка объектов"""
    with Pool(processes) as pool:
        return pool.map(pickle.dumps, data_list)
 
# Пример использования
large_data = [{"id": i, "data": list(range(1000))} for i in range(100)]
serialized = parallel_serialize(large_data)

Практические примеры и рекомендации



Теория — это прекрасно, но давайте погрузимся в практику. За годы работы с Python я накопил коллекцию решений для различных сценариев сериализации. Некоторые из них спасали проекты в самый последний момент, а некоторые стали частью регулярной разработки.

Сохранение состояния приложения



Сохранение состояния приложения между запусками — типичная задача для сериализации. Вот простой, но элегантный подход с использованием контекстного менеджера:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import pickle
import os
from contextlib import contextmanager
 
@contextmanager
def saved_state(filename, default=None):
    """Контекстный менеджер для сохранения состояния приложения."""
    state = default
    if os.path.exists(filename):
        try:
            with open(filename, 'rb') as f:
                state = pickle.load(f)
        except Exception as e:
            print(f"Ошибка загрузки состояния: {e}")
    
    try:
        yield state
    finally:
        with open(filename, 'wb') as f:
            pickle.dump(state, f)
 
# Пример использования
with saved_state('app_state.pkl', default={}) as state:
    state['counter'] = state.get('counter', 0) + 1
    print(f"Приложение запущено {state['counter']} раз")
    
    # Работа с состоянием
    if 'last_run' not in state:
        state['last_run'] = []
    state['last_run'].append(time.time())
Этот паттерн обеспечивает автоматическое сохранение состояния при выходе из блока with, даже если внутри возникнет исключение. Я использовал похожий подход в утилите для работы с API, которая хранила кеш ответов между запусками.

Кастомная сериализация сложных объектов



Когда дело касается сериализации сложных объектов в JSON, часто нужно создавать специальные преобразователи. Рассмотрим пример системы с объектами разных типов:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import json
from datetime import datetime, date
import uuid
 
class ComplexJSONEncoder(json.JSONEncoder):
    """Расширенный JSON энкодер для работы со сложными типами."""
    def default(self, obj):
        if isinstance(obj, datetime):
            return {"_type": "datetime", "iso": obj.isoformat()}
        elif isinstance(obj, date):
            return {"_type": "date", "iso": obj.isoformat()}
        elif isinstance(obj, uuid.UUID):
            return {"_type": "uuid", "hex": obj.hex}
        elif hasattr(obj, "to_json"):
            # Для объектов, реализующих метод to_json
            return obj.to_json()
        return super().default(obj)
 
def complex_json_decoder(json_dict):
    """Декодер для восстановления спецальных типов из JSON."""
    if "_type" in json_dict:
        obj_type = json_dict["_type"]
        if obj_type == "datetime":
            return datetime.fromisoformat(json_dict["iso"])
        elif obj_type == "date":
            return date.fromisoformat(json_dict["iso"])
        elif obj_type == "uuid":
            return uuid.UUID(json_dict["hex"])
    return json_dict
 
# Пример использования
data = {
    "id": uuid.uuid4(),
    "created_at": datetime.now(),
    "expires_on": date.today()
}
 
# Сериализация
json_str = json.dumps(data, cls=ComplexJSONEncoder, indent=2)
print(json_str)
 
# Десериализация
restored = json.loads(json_str, object_hook=complex_json_decoder)
print(f"Восстановленный UUID: {restored['id']}")
print(f"Восстановленная дата: {restored['expires_on']}")
Этот подход особено полезен, когда вы работаете с API, которые должны возвращать JSON, но внутри вашего приложения используются сложные типы данных. Я встречал ситуации, когда разработчики копировали значения из объектов в словари вручную, вместо того чтобы создать универсальный сериализатор один раз.

Потоковая обработка при ограниченной памяти



Иногда вам нужно обрабатывать данные размером больше доступной памяти. В таких случаях можно использовать потоковую обработку с генераторами:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import json
 
def process_large_json_file(input_file, output_file, transform_func):
    """Потоковая обработка большого JSON-файла с преобразованием каждого объекта."""
    with open(input_file, 'r') as fin, open(output_file, 'w') as fout:
        # Читаем открывающую скобку
        assert fin.read(1) == '['
        
        # Запишем открывающую скобку в выходной файл
        fout.write('[')
        
        first_item = True
        buffer = ''
        bracket_count = 0
        in_string = False
        escape_next = False
        
        while True:
            char = fin.read(1)
            if not char:  # Конец файла
                break
                
            buffer += char
            
            # Отслеживаем, находимся ли мы внутри строки
            if char == '"' and not escape_next:
                in_string = not in_string
            elif char == '\\' and in_string:
                escape_next = True
                continue
            
            if not in_string:
                if char == '{':
                    bracket_count += 1
                elif char == '}':
                    bracket_count -= 1
                    
                    # Если закрыли объект верхнего уровня
                    if bracket_count == 0:
                        # Обработаем объект
                        obj = json.loads(buffer)
                        transformed = transform_func(obj)
                        
                        # Запишем разделитель, если это не первый объект
                        if not first_item:
                            fout.write(',')
                        first_item = False
                        
                        # Запишем преобразованный объект
                        fout.write(json.dumps(transformed))
                        buffer = ''
            
            escape_next = False
            
        # Закроем массив
        fout.write(']')
 
# Пример использования
def transform_user(user):
    """Пример функции преобразования."""
    # Добавим вычисляемое поле
    if 'first_name' in user and 'last_name' in user:
        user['full_name'] = f"{user['first_name']} {user['last_name']}"
    return user
 
# Обработка файла с миллионами пользователей
process_large_json_file('users.json', 'transformed_users.json', transform_user)
Этот код позволяет обработать файл JSON, содержащий миллионы объектов, без необходимости загружать весь файл в память. Мы читаем файл посимвольно, отслеживая структуру JSON, и как только находим полный объект - обрабатываем его и записываем в выходной файл. Я написал похожую утилиту для клиента, которому нужно было трансформировать JSON-файл размером 50 ГБ на машине с 4 ГБ памяти. Без потоковой обработки эта задача была бы просто невозможна.

Версионирование сериализованных данных



Одна из самых больших проблем сериализации — изменение формата данных со временем. Как десериализовать данные, сохранённые год назад, если класс с тех пор изменился? Вот элегнтное решение с прозрачным версионированием:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
class VersionedModel:
    __schema_version__ = 1
    
    def to_dict(self):
        """Преобразует объект в словарь для сериализации."""
        data = {
            "__schema_version__": self.__schema_version__,
            # Данные конкретной версии
        }
        # Заполняем данные в соответсвии с текущей версией
        data.update(self._to_dict_v1())
        return data
    
    def _to_dict_v1(self):
        """Реализация сериализации для версии 1."""
        raise NotImplementedError()
    
    @classmethod
    def from_dict(cls, data):
        """Создаёт объект из словаря с учётом версии."""
        version = data.get("__schema_version__", 1)
        
        if version == 1:
            obj = cls._from_dict_v1(data)
        else:
            raise ValueError(f"Неизвестная версия схемы: {version}")
        
        return obj
    
    @classmethod
    def _from_dict_v1(cls, data):
        """Реализация десериализации для версии 1."""
        raise NotImplementedError()
 
# Пример использования
class User(VersionedModel):
    __schema_version__ = 2
    
    def __init__(self, username, email=None, display_name=None):
        self.username = username
        self.email = email
        self.display_name = display_name
    
    def _to_dict_v1(self):
        """Первая версия формата."""
        return {
            "username": self.username,
            "email": self.email
        }
    
    def _to_dict_v2(self):
        """Вторая версия добавляет display_name."""
        data = self._to_dict_v1()
        data["display_name"] = self.display_name
        return data
    
    def to_dict(self):
        """Переопределяем для поддержки новой версии."""
        data = {
            "__schema_version__": self.__schema_version__,
        }
        # Используем последнюю версию сериализации
        data.update(self._to_dict_v2())
        return data
    
    @classmethod
    def _from_dict_v1(cls, data):
        """Десериализация из формата v1."""
        return cls(
            username=data["username"],
            email=data["email"]
        )
    
    @classmethod
    def _from_dict_v2(cls, data):
        """Десериализация из формата v2."""
        user = cls._from_dict_v1(data)
        user.display_name = data.get("display_name")
        return user
    
    @classmethod
    def from_dict(cls, data):
        """Переопределяем для поддержки разных версий."""
        version = data.get("__schema_version__", 1)
        
        if version == 1:
            return cls._from_dict_v1(data)
        elif version == 2:
            return cls._from_dict_v2(data)
        else:
            raise ValueError(f"Неизвестная версия схемы: {version}")
Этот подход позволяет бесшовно поддерживать обратную совместимость с данными, созданными в разных версиях вашего приложения. Я использовал подобную схему в проекте, который развивался на протяжении нескольких лет, и это спасло нас от необходимости миграции данных при каждом изменении модели.

Сериализация в веб-фреймворках



Если вы работаете с веб-фреймворками типа Django или Flask, вам повезло — в них уже встроены инструменты для сериализации.

В Django REST Framework, например, сериализаторы — это мощные инструменты для преобразования моделей в JSON и обратно:

Python
1
2
3
4
5
6
7
8
from rest_framework import serializers
from myapp.models import User
 
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'is_active']
        read_only_fields = ['id']
Такой сериализатор автоматически позаботится о преобразовании полей, валидации и даже вложенных отношениях. Однажды я потратил два дня, написав кастомный сериализатор для сложной модели, прежде чем коллега показал, что это можно сделать в пять строк с помощью ModelSerializer. Урок усвоен!

Валидация данных при десериализации



Важный аспект, который часто упускают из виду — валидация данных при десериализации. Представьте, что вы получаете JSON от клиентской части приложения. Можете ли вы доверять этому JSON?

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def deserialize_user_data(json_data):
    try:
        data = json.loads(json_data)
    except json.JSONDecodeError:
        raise ValueError("Некорректный формат JSON")
    
    # Проверяем обязательные поля
    required_fields = ['username', 'email']
    for field in required_fields:
        if field not in data:
            raise ValueError(f"Отсутствует обязательное поле: {field}")
    
    # Валидируем email
    email = data['email']
    if not re.match(r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', email):
        raise ValueError(f"Некорректный email: {email}")
    
    return data
Библиотека Pydantic упрощает такую валидацию:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pydantic import BaseModel, EmailStr, validator
 
class UserData(BaseModel):
    username: str
    email: EmailStr
    age: int = None  # Опциональное поле
    
    @validator('username')
    def username_must_be_valid(cls, v):
        if len(v) < 3:
            raise ValueError('Имя пользователя должно содержать не менее 3 символов')
        return v
 
# Десериализация с автоматической валидацией
try:
    user = UserData.parse_raw('{"username": "al", "email": "not-an-email"}')
except Exception as e:
    print(f"Ошибка валидации: {e}")
Pydantic стал моим стандартным инструментом для валидации JSON в API. Он не только проверяет типы и соответсвие правилам, но и преобразует данные в удобные для работы объекты.

Выбор правильного формата сериализации



Как выбрать оптимальный формат? Вот моя шпаргалка:

1. JSON: если требуется совместимость с другими системами, читаемость, работа с веб-API.
2. MessagePack: когда нужна производительность и компактность, но сохраняя совместимость с разными языками.
3. Pickle: для внутреннего использования в Python, когда нужна поддержка произвольных объектов.
4. Protocol Buffers: для высоконагруженных систем с фиксированными схемами данных.
5. YAML: для конфигурационных файлов, которые будут читать и редактировать люди.

Я обжёгся, выбрав pickle для хранения данных, к которым потом понадобился доступ из JavaScript. Пришлось писать конвертеры туда-обратно. Поэтому сейчий мой проект начинается с вопроса: "Кто ещё будет использовать эти данные?"

Сериализация данных для хранения в txt файле
Здравствуйте! Имеется список: students= Значение rate может быть как пустым так и...

Десериализация json как в ASP.Net MVC
Всем доброго дня. Недавно только вот начал разбираться с Python и Django, до этого довольно тесно...

Десериализация кортежа
У меня есть кортеж, который я сериализую. a = (1, ) print(json.dumps(a)) после чего...

Десериализация объекта
Здравствуйте, что не так? Надо сделать десериализацию объекта &quot;c&quot;, но он пишет что объект класса...

Сериализация таблицы QTableWidget
Добрый день. Как лучше всего сохранить таблицу QTableWidget с помощью pickle? Использую PyQt5...

Сериализация объекта
Подскажите, что не так с кодом. при запуске в терминале выдаёт ошибку: TypeError: an integer is...

Сериализация несвязанных моделей
есть база данных, импортированная из сайта на php. На ее основе делаю api с помощью django rest...

сериализация используя json ошибка
использую pycharm кодировка выставлена utf-8 есть клиент и сервер на сервере посылаем команду...

Деструктор. Сериализация
добавьте в описание классов, деструкторы; модифицируйте методы своих классов для учёта транзакций;...

Сериализация произвольных объектов
Доброго времени суток! Изучаю python django. В одном задачи у меня выводится ошибка. не могу его...

Сериализация набора объектов, относящихся к разным классам моделей
Здравствуйте! Не знаю как по-другому решить вопрос о сериализации набора объектов, относящихся к...

Как из Python скрипта выполнить другой python скрипт?
Как из Python скрипта выполнить другой python скрипт? Если он находится в той же папке но нужно...

Метки protobuf, python
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Популярные LM модели ориентированы на увеличение затрат ресурсов пользователями сгенерированного кода (грязь -заслуги чистоплюев).
Hrethgir 12.06.2025
Вообще обратил внимание, что они генерируют код (впрочем так-же ориентированы разработчики чипов даже), чтобы пользователь их использующий уходил в тот или иной убыток. Это достаточно опытные модели,. . .
Топ10 библиотек C для квантовых вычислений
bytestream 12.06.2025
Квантовые вычисления - это та область, где теория встречается с практикой на границе наших знаний о физике. Пока большая часть шума вокруг квантовых компьютеров крутится вокруг языков высокого уровня. . .
Dispose и Finalize в C#
stackOverflow 12.06.2025
Работая с C# больше десяти лет, я снова и снова наблюдаю одну и ту же историю: разработчики наивно полагаются на сборщик мусора, как на волшебную палочку, которая решит все проблемы с памятью. Да,. . .
Повышаем производительность игры на Unity 6 с GPU Resident Drawer
GameUnited 11.06.2025
Недавно копался в новых фичах Unity 6 и наткнулся на GPU Resident Drawer - штуку, которая заставила меня присвистнуть от удивления. По сути, это внутренний механизм рендеринга, который автоматически. . .
Множества в Python
py-thonny 11.06.2025
В Python существует множество структур данных, но иногда я сталкиваюсь с задачами, где ни списки, ни словари не дают оптимального решения. Часто это происходит, когда мне нужно быстро проверять. . .
Работа с ccache/sccache в рамках C++
Loafer 11.06.2025
Утилиты ccache и sccache занимаются тем, что кешируют промежуточные результаты компиляции, таким образом ускоряя последующие компиляции проекта. Это означает, что если проект будет компилироваться. . .
Настройка MTProxy
Loafer 11.06.2025
Дополнительная информация к инструкции по настройке MTProxy: Перед сборкой проекта необходимо добавить флаг -fcommon в конец переменной CFLAGS в Makefile. Через crontab -e добавить задачу: 0 3. . .
Изучаем Docker: что это, как использовать и как это работает
Mr. Docker 10.06.2025
Суть Docker проста - это платформа для разработки, доставки и запуска приложений в контейнерах. Контейнер, если говорить образно, это запечатанная коробка, в которой находится ваше приложение вместе. . .
Тип Record в C#
stackOverflow 10.06.2025
Многие годы я разрабатывал приложения на C#, используя классы для всего подряд - и мне это казалось естественным. Но со временем, особенно в крупных проектах, я стал замечать, что простые классы. . .
Разработка плагина для Minecraft
Javaican 09.06.2025
За годы существования Minecraft сформировалась сложная экосистема серверов. Оригинальный (ванильный) сервер не поддерживает плагины, поэтому сообщество разработало множество альтернатив. CraftBukkit. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru