Кодирование — это преобразование данных из одного представления в другое по фиксированному, заранее известному правилу: чтобы данные можно было передать, сохранить или обработать программой. Декодирование — обратное преобразование, которое восстанавливает исходные данные. У программиста термин встречается в разных задачах: кодирование текста в байты (символьные кодировки), кодирование бинарных данных текстом (base64), кодирование спецсимволов в URL (percent-encoding) и кодирование структур данных для передачи (сериализация). Ниже — как это устроено на практике и чем кодирование НЕ является.
Содержание
- Кодирование, сжатие и шифрование — в чем разница
- Кодирование текста в байты: коротко о символьных кодировках
- Base64: как кодируют бинарные данные текстом
- URL-encoding (percent-encoding): кодирование спецсимволов в адресах
- Сериализация: кодирование структур данных
- Типичные ошибки кодирования и декодирования
- Выводы
- Где применяется / связь с практикой
- FAQ
Кодирование, сжатие и шифрование — в чем разница
Три операции легко путают, потому что все три меняют байты на входе. Но у них разная цель, и это определяет, обратимы ли они без дополнительных данных.
| Операция | Цель | Нужен ли секрет для обратного шага | Пример |
|---|---|---|---|
| Кодирование | Представить данные в другом, совместимом формате | Нет, только знание схемы кодирования | base64, UTF-8, JSON |
| Сжатие | Уменьшить размер данных | Нет, только знание алгоритма (упаковщика) | gzip, zip, deflate |
| Шифрование | Скрыть содержимое от посторонних | Да, нужен ключ | AES, ChaCha20 |
Кодирование и сжатие обратимы любым, кто знает алгоритм — секретов там нет. Base64 иногда по ошибке называют «шифрованием»: это неверно, любой декодирует base64-строку за секунду без пароля. Шифрование — единственная из трех операций, которая реально что-то скрывает, и только с ключом.
Кодирование текста в байты: коротко о символьных кодировках
Текст в памяти компьютера — это байты, а какому символу соответствует байт (или несколько байтов), определяет кодировка. Здесь важно развести два понятия: кодовая точка — номер символа в стандарте Unicode (например, у буквы «Я» это U+042F), и кодировка (encoding) — правило, как этот номер записать байтами. Самая распространенная сегодня кодировка — UTF-8: она превращает каждую кодовую точку в 1-4 байта, латиница занимает 1 байт (совместима с ASCII), кириллица — 2 байта.
Цепочка на примере: символ «Я» -> кодовая точка U+042F -> в UTF-8 это байты D0 AF.
s = "Я"
b = s.encode("utf-8")
print(b)
# Вывод: b'\xd0\xaf' - ровно 2 байта, как и ожидается для кириллицы в UTF-8
print(b.decode("utf-8"))
# Вывод: Я - декодирование восстановило исходный символ
Если декодировать байты не той кодировкой, которой их закодировали, получаются «кракозябры» либо UnicodeDecodeError. Разбор конкретных кодировок (Windows-1251, KOI8-R, UTF-8 vs UTF-16) — тема отдельной статьи; здесь это лишь один из видов кодирования.
Base64: как кодируют бинарные данные текстом
Base64 нужен, когда бинарные данные (файл, изображение, ключ) нужно передать через канал, который гарантированно понимает только текст: email, JSON, XML, часть URL. Base64 берет каждые 3 байта исходных данных и представляет их 4 текстовыми символами из алфавита A-Z, a-z, 0-9, +, / (плюс = для выравнивания хвоста). В результате данные раздуваются примерно на 33% — это плата за то, что результат гарантированно текст.
import base64
data = "Привет, мир!".encode("utf-8")
encoded = base64.b64encode(data)
print(encoded)
# Вывод: b'0J/RgNC40LLQtdGCLCDQvNC40YAh'
decoded = base64.b64decode(encoded).decode("utf-8")
print(decoded)
# Вывод: Привет, мир! - byte-в-byte исходная строка
Типичная ошибка — обрезанная или битая base64-строка (например, скопирована не полностью):
broken = encoded[:-1] # отрезали последний символ, длина больше не кратна 4
try:
base64.b64decode(broken)
except Exception as e:
print(type(e).__name__, e)
# Вывод: Error Incorrect padding (binascii.Error)
Исправление — проверять длину строки перед декодированием (кратна 4, с учетом =) и не резать base64 вручную. Важная граница: по умолчанию base64.b64decode молча пропускает символы вне алфавита base64 вместо того, чтобы падать с ошибкой; для строгой проверки входа нужен validate=True.
URL-encoding (percent-encoding): кодирование спецсимволов в адресах
У URL есть служебные символы (/, ?, =, &, пробел, кириллица и другие небезопасные для адресной строки байты), которые нельзя вставить в адрес как есть — браузер или сервер прочитает их как часть структуры URL, а не как данные. Percent-encoding заменяет такой байт на % и его шестнадцатеричный код.
from urllib.parse import quote, unquote, quote_plus
path = "привет мир/тест?x=1"
encoded = quote(path)
print(encoded)
# Вывод: %D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82%20%D0%BC%D0%B8%D1%80/%D1%82%D0%B5%D1%81%D1%82%3Fx%3D1
print(unquote(encoded))
# Вывод: привет мир/тест?x=1 - декодирование вернуло исходную строку
Обратите внимание: слэш в строке остался как есть. quote() по умолчанию считает / безопасным символом (safe='/') — это стандартный разделитель сегментов пути, его кодировать не нужно. Если нужно закодировать и слэш — например, он часть значения, а не разделителя, — передают safe=''.
Для строки запроса (после ?) чаще нужна другая функция — quote_plus: она кодирует пробел не как %20, а как +, как того требует формат application/x-www-form-urlencoded в HTML-формах:
print(quote_plus("a b&c"))
# Вывод: a+b%26c
Смешивать quote и quote_plus в одном URL не стоит — формат пробела должен совпадать с тем, что ожидает декодер.
Сериализация: кодирование структур данных
Сериализация — частный случай кодирования: превращение объекта или структуры данных (словарь, список, объект класса) в поток байтов или текста для передачи по сети либо сохранения в файл. Обратная операция — десериализация.
Самый частый формат в вебе — JSON: он текстовый, человекочитаемый, одинаково понимается практически любым языком программирования.
import json
payload = {"name": "Отус", "ok": True, "n": 5}
text = json.dumps(payload, ensure_ascii=False)
print(text)
# Вывод: {"name": "Отус", "ok": true, "n": 5}
restored = json.loads(text)
print(restored)
# Вывод: {'name': 'Отус', 'ok': True, 'n': 5}
В Python есть и формат pickle — сериализует практически любой объект языка, но результат бинарный и понятен только Python. Граница безопасности: pickle.loads() на непроверенных данных — риск выполнения произвольного кода, формат позволяет описать вызов функции при восстановлении объекта. Десериализовывать pickle из недоверенного источника (например, от пользователя через API) небезопасно; для межсервисного обмена поэтому предпочтительнее JSON.
Типичные ошибки кодирования и декодирования
| Симптом | Частая причина | Что проверить |
|---|---|---|
UnicodeDecodeError |
Байты декодируют не той кодировкой, в которой их записали | Явно задать encoding="utf-8" при записи и чтении файла |
| «Кракозябры» вместо текста | Один байтовый поток открыт в двух разных кодировках | Сверить кодировку источника (Content-Type: charset=, BOM) и чтения |
binascii.Error: Incorrect padding |
Base64-строка обрезана или повреждена при копировании | Длина строки кратна 4 с учетом =, не резать base64 вручную |
Двойное кодирование URL (%2520 вместо %20) |
Строку закодировали percent-encoding дважды подряд | Кодировать данные один раз, перед вставкой в URL |
Неожиданное поведение pickle.loads на чужих данных |
Untrusted-вход для формата, не рассчитанного на это | Для межсервисного обмена — JSON, pickle — только для своего кэша |
Выводы
- Кодирование — это представление данных по известному правилу, без секрета; декодирование — обратный шаг. Это НЕ шифрование и НЕ сжатие, хотя все три меняют байты.
- Символьная кодировка (например, UTF-8) — лишь один вид кодирования: превращение кодовой точки Unicode в байты.
- Base64 превращает бинарные данные в текст ценой примерно 33% увеличения размера — для каналов, которые понимают только текст.
- Percent-encoding (URL-encoding) защищает служебные символы URL;
quoteиquote_plusкодируют пробел по-разному, смешивать их нельзя. - Сериализация (JSON, pickle) — кодирование структур данных для передачи; десериализация untrusted pickle-данных — риск безопасности, для межсервисного обмена лучше JSON.
Где применяется / связь с практикой
Освойте тему на практике
Работа с кодированием данных — база системного программирования: сетевые протоколы, файловые форматы, API между сервисами построены на точном понимании, как данные представлены байтами и как это представление меняется на каждом шаге. Тема разбирается на курсе System Programming — там кодирование, сериализация и работа с бинарными протоколами разбираются на практических задачах, а не только в теории. Если пока не уверены, что нужно именно системное программирование, — можно начать с открытых уроков Otus: расписание открытых уроков обновляется регулярно, там показывают разбор похожих задач вживую.
FAQ
Base64 — это шифрование?
Нет. Base64 не использует ключ и не скрывает данные: любой может декодировать base64-строку, зная только алгоритм. Это кодирование — представление байтов текстом, а не защита от чтения.
Почему после кодирования в URL строка стала длиннее в несколько раз?
Percent-encoding заменяет каждый «небезопасный» байт на три символа (%XX), поэтому нелатинский текст (например, кириллица в UTF-8) может вырасти в 3-9 раз по длине. Это нормальное поведение схемы, а не ошибка.
Чем сериализация отличается от кодирования вообще?
Сериализация — это кодирование именно структур данных (объектов, списков, словарей) в поток байтов или текста для передачи либо хранения. Кодирование — более широкое понятие: оно применимо и к отдельному символу, и к произвольным бинарным данным, не только к структурам.



