Содржина на објавата
Вы знаете, что строки в Python можно кодировать и декодировать в разные кодировки. >>> s = 'Привет' >>> s.encode() # в байты b'\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' >>> s.encode('ascii') # в ASCII (если получится) UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128) >>> s.encode('euc_jp') # японская кодировка b'\xa7\xb1\xa7\xe2\xa7\xda\xa7\xd3\xa7\xd6\xa7\xe4' >>> s.encode('hz') # Simplified Chinese b"~{'1'b'Z'S'V'd~}" И другие... А можно ли добавить свою кодировку в этот список? Можно! И сейчас мы это сделаем. Давайте добавим ZIP-кодировку из Python2, о которой мы говорили в прошлом посте. Для начала нам нужен алгоритм. Я хочу сжимать строку через ZIP и после получения байтов преобразовывать их в строку через base64 (можно и без base64). Получится такой код: import zlib, base64 >>> orig = 'hello python' >>> compressed = zlib.compress(orig.encode(), 5) >>> compresed_b = base64.encodebytes(compressed) >>> print(compresed_b) b'eF7LSM3JyVcoqCzJyM8DAB7wBNc=' Да, строка получилась длинней чем была. Но мы помним, что всё будет иначе если исходная строка большая. Обратный алгоритм декодирования >>> compressed = base64.decodebytes(compresed_b) >>> restored = zlib.decompress(compressed).decode() >>> orig == restored True Отлично!😎 Теперь, чтобы создать кодек на базе этих алгоритмов, следует воспользоваться функций codecs.register(). В неё подаётся имя функции которая должна вернуть объект codecs.CodecInfo. Данный объект будет содержать две функции - кодирование и декодирование. Это и будет наш кодек. Давайте назовём наш кодек просто "z". Тогда его создание будет выглядеть как-то так: import zlib, base64, codecs def z_encode(data): return base64.encodebytes(zlib.compress(data.encode(), 5)), 0 def z_decode(data): return zlib.decompress(base64.decodebytes(data)).decode(), 0 def z_search(encoding_name): return codecs.CodecInfo(z_encode, z_decode, name='z') codecs.register(z_search) Тестим! >>> s = 'Hello New codec!' >>> s_enc = s.encode('z') >>> print(s_enc) b'eF7zSM3JyVfwSy1XSM5PSU1WBAAvxwV+\n' Теперь обратно >>> s_enc.decode('z') 'Hello New codec!' А теперь практика!. Сжимаем JSON со списком файлов >>> from pathlib import Path >>> import json >>> files = list(map(str, list(Path('~/Documents').expanduser().glob('**/*')))) >>> print(len(files)) 5390 >>> text = json.dumps(files) >>> print(len(text)) 513839 >>> enc = text.encode('z') >>> print(len(enc)) 53317 Профит почти в 10 раз! Можно еще уменьшить размер если обойтись без BASE64. Но тогда вы получите чистые байты и как строку их передать уже не получится. PS. А вот стандартный и самый короткой способ для ZIP-сжатия байтов в Python3 >>> import codecs >>> codecs.encode(my_bytes, 'zip')) (спасибо @amarovita за пример кода) #tricks