TGTGInsighttelegram intelligenceLIVE / telegram public index
Назад кон каналите
Python Заметки avatar

TGINSIGHT CHAT

Python Заметки

@pythonotes

Education

Интересные заметки и обучающие материалы по Python Контакт: @paulwinex ⚠️ Рекламу на канале не делаю!⚠️ Хештеги для поиска: #tricks #libs #pep #basic #regex #qt #django #2to3 #source #offtop

Претплатници2,220Тековни претплатници
Следени објави384Број на индексирани објави
Неодамнешен опфат26,200Збир на неодамнешни прегледи
Неодамнешни објави

Неодамнешни објави

Ознака: #libs · 124 објави

当前筛选 #libs清除筛选

Објавено 10 мај

Есть один интересный момент с запаковкой строк. >>> struct.pack(f'=6s', b'python') b'python' >>> 'python'.encode() b'python' Хммм..., struct создает тип bytest но при этом для строки просит тоже bytes. На выходе получаем опять bytes без изменений. В чем логика? Ведь ничего же не поменялось! Зачем тогда нам вообще нужен struct если encode делает тоже самое? Если вам требуется записать просто одну строку какой-то рандомной длины, то паковка тут не нужна. Можете писать любые байты в файл как угодно без запаковки. А смысл паковки в том, что с помощью формата мы гарантируем правильную длину всех частей записываемых данных. Если данных слишком много, они обрезаются, если мало, то лишнее заполнится нулевым байтом. Ведь мы читаем данные, ориентируясь на заведомо установленные и предсказуемые позиции байтов в файле. >>> struct.pack(f'=3s', b'python') b'pyt' >>> struct.pack(f'=10s', b'python') b'python\x00\x00\x00\x00' Формат запаковки нужен как раз для того, чтобы фиксировать разметку файла на основе размера используемых типов данных. Вот абстрактный пример спецификации файла: ◽️128 байт : какой-то заголовок (str) ◽️8 байт : количество элементов (int) ◽️[4 байта] : массив данных (тип float до конца файла по 4 байта) Теперь мы знаем как записывать и считывать этот файл, у нас есть его спецификация. Просто берëм нужный диапазон байт и распаковываем в нужный тип данных. Если мы хоть на один байт сместимся, то данные распакуются некорректно. Когда размер данных заранее неизвестен, то, обычно, перед непосредственно данными пишут сколько они занимают места до следующего блока данных, как в моём примере. В более простых случаях это необязательно. data1 = [...] data2 = [...] struct.pack(f'=Q{len(data1)}i', len(data1), data1) struct.pack(f'=Q{len(data2)}i', len(data2), data2) Начиная с начала файлы мы точно знаем что следующие 8 байт (Q = unsigned long long) это число с количеством элементов, записанных сразу после него. И точно знаем где находится следующий блок данных. ❗️Еще раз, помимо преобразования разных типов в байты, модуль struct занимается форматированием или разметкой данных в файле. Именно это и означает что разметка находится вне файла с данными. И это критически важный момент при создании бинарных файлов! #libs

1,670 views

Hashtags

Теперь запакуем строку. В этом случае следует передавать тип данных bytes. >>> struct.pack('=s', b'a') b'a' Для записи слова следует указывать количество символов. >>> struct.pack('=5s', b'hello') b'hello' Кстати, запакованный вид соответствует исходному тексту. Всё верно, символ есть в таблице ASCII, то есть его код попадает в диапазон 0-127, он может быть записан одним байтом и имеет визуальное представление. А вот что будет если добавить символ вне ASCII >>> struct.pack(f'=s', b'ё') SyntaxError: bytes can only contain ASCII literal characters. Ошибка возникла еще на этапе создания объекта bytes, который не может содержать такой символ. Поэтому надо кодировать эти байты из строки. >>> enc = 'ёжик'.encode('utf-8') >>> struct.pack(f'={len(enc)}s', enc) b'\xd1\x91\xd0\xb6\xd0\xb8\xd0\xba' Заметьте, длина такой строки в байтах отличается от исходной длины, так как символы вне ASCII записываются двумя байтами и более. Поэтому здесь формат создаём на лету, используя получившуюся длину как каунтер токена. #libs#basic

1,620 views

Hashtags

Објавено 16 апр.

А как вам идея сделать свойство для модуля?! К сожалению, тут без внешних библиотек не обойтись. Но выглядит интересно! # my_module.py from mprop import mproperty @mproperty def x(mod): print(f"Prop from '{mod.__name__}'") return 2+2 По аналогии со свойствами класса и инстанса в функцию первым аргументом прилетает объект текущего модуля. Теперь обращаемся к функции как к объекту модуля: >>> import my_module >>> my_module.x Prop from 'my_module' 4 #tricks#libs

2,450 views

Hashtags

Објавено 31 мар.

Порой админу проще написать огромный bash-скрипт с запросами в БД и парсингом через регулярки чем пытаться тоже самое изобразить в Python. Тоже самое верно и в обратном случае. Даже простые shell команды порой удобней записать в Python скрипт чем на bash. Правда, в обоих случаях выглядит это всё не очень. Если сталкивались с таким, то поймёте о чем я😢 Специально для вас сделал подборку библиотеки для работы с shell из Python. Чтобы ваш код оставался красивым и читабельным! ➡️ sh Переносим bash синтаксис в Python. Удобно и немногословно. Ранее я уже рассказывал про этот модуль, можно глянуть в этом посте. ➡️plumbum Аналогичен sh но со своими плюшками. Например встроенная колоризация вывода ➡️pexpect Библиотека для интерактивного взаимодействия с процессом через stdin/stdout. Нашел небольшой гайд на русском. ➡️shell_command Еще одна библиотека для вызова shell-команд. Ориентируется на безопасность вызываемого кода и заточена на удобство для админов. Бонусом ➡️envoy Обёртка вокруг subprocess делающая его использование еще проще и минималистичней. _______________ Кстати, до Python 2.6 вместо subprocess была библиотека commands. Выглядит достаточно аскетично) #libs

2,190 views

Hashtags

Објавено 22 мар.

Иногда хочется чтобы в качестве объекта передачи данных был удобный класс но не хочется (или нет возможности) писать сераиализатор в JSON для него. Идеально было бы сделать класс, который сам умел бы сериализоваться в JSON дефолтным модулем без указания дополнительных сериализаторов. Как это сделать? Стандартный модуль JSON умеет правильно сериализовать стандартные типы. Но нам нужен кастомный класс с удобными методами и свойствами. Ответ очевиден - наследуемся от стандартного типа! В качестве базового типа возьмем словарь. Например, мне нужен класс некоего абстрактного элемента списка с именем и индексом. Тогда реализация может быть такой. class Item(dict): def __init__(self, name, index=0): super().__init__(name=name, index=index) @property def name(self): return self['name'] @name.setter def name(self, value): self['name'] = value @property def index(self): return self['index'] @index.setter def index(self, value): self['index'] = value def __setitem__(self, key, value): if key not in ['index', 'name']: raise KeyError super().__setitem__(key, value) Я добавил два свойства с простым переназначением данных в словарь. Но предполагается, что там будут проверки значений и иные вычисления. Еще хорошо бы добавить методы __str__ и __repr__. >>> it = Item('item name') >>> it.name 'item name' >>> it.index 0 Также можно добавить любые методы классу. Например я переопределил __setitem__ чтобы нельзя было задать иные ключи. >>> it['key'] = 123 KeyError Хотя, можно сделать как-то иначе. К примеру, все отличные от основных ключи записывать в отдельный ключ. def __setitem__(self, key, value): if key not in ['index', 'name']: self['meta'][key] = value else: super(Item, self).setitem(key, value) Ну а главная особенность этого класса в том, что он легко понимается стандартным модулем json (конечно, если значения ключей это тоже стандартные типы или наследованные от них) >>> json.dumps(item) '{"index": 2, "name": "item name"}' Самый очевидный пример, использование в библиотеке requests. Передавая объект в аргумент json, мы не можем повлиять на его сериализацию, то есть добавить класс-сериализатор. Там ожидается готовый словарь или иной совместимый тип. import requests requests.post(url, json=item) А вот так выглядит альтернатива с методом toJson() requests.post(url, data=item.toJson(), headers={'Content-Type': 'application/json'}) А ещё ничто не мешает нам в любой момент конвертнуть наш класс в обычный словарь >>> dict(item) {"index": 2, "name": "item name"} Не спорю, возможно есть более "умные" решения этой задачи 🤓 Но, тем не менее, аналогичным образом работает стандартный collections.namedtuple. Он тоже наследуется от стандартного tuple, расширяет его функционал и сериализуется без дополнительных средств. Для более сложных случаев можно посмотреть на библиотеку dataclasses-json, которая поможет сериализовать dataclasses. #tricks#libs

2,500 views

Hashtags

Објавено 19 мар.

Стандартная Django админка работает стабильно но не могу сказать что она меня устраивает. Да, есть базовый набор стандартного функционала, но чего-то всегда не хватает. Может автокомплитов а может тёмной темы. 😎 Долгое время я использовал DjangoSuit, но проект заглох на невыпущенной альфе 2й версии которая в Django3 и вовсе не поддерживается. Что же можно сегодня посоветовать? На сегодняшний день у меня два фаворита: 🚀 DjangoJET 🌎 сайт 🗄 репозиторий ▶️ видео Крутая и красивая админка с кучей плюшек. ▫️автокомплиты с AJAX подгрузкой ▫️темы ▫️дашборды ▫️респонсив ▫️кастомизация панелей прямо в админке Стоит денег для коммерческих продуктов. Для опенсорса бесплатно (AGPL)! 🎷Django Jazzmin 🗄репозиторий Не такая пафосная но от этого не менее крутая админка. ▫️полностью кастомизируется ▫️много готовых тем и возможность собрать свою прямо в админке ▫️Bootsrtap Model окна вместо всплывающих окон ▫️интегрирован Select2 ▫️респонсив Знаете еще крутые админки? Напишите в комментах! #django#libs

2,060 views

Hashtags

Објавено 17 фев.

Ранее я показал как упаковать ваше Python-приложение в ZIPAPP. В дополнение к этой теме покажу ещё один способ как достать изображение из архива, не сохраняя его на диск и сразу перегнать в класс PIL.Image для дальнейших манипуляций. Что есть ресурс в данном контексте? Это любой объект который можно прочитать как файл. В Python 3.7появился новый стандартный способ работы с ресурсами внутри пакетов. Это модуль importlib.resources. Его следует использовать и для случаев с контейнерами (ZIP, EGG) и для обычных пакетов. Для начала импортнём нужные модули from importlib.resources import read_binary from PIL import Image import io Читаем файл ресурса из пакета data = read_binary("package_name", "image.jpg") Создаём класс Image img = Image.open(io.BytesIO(data)) Картинка загружена в память, можно с ней что-то делать img.thumbnail((200, 200)) И после изменений сохранить в файл img.save(path, 'JPG') или использовать еще как-то img.show() Модуль получил бекпорт для старых версий в виде стороннего пакета importlib_resources. До появления этого модуля использовался модуль pkg_resources, входящий в состав setuptools. Но он теперь неактуален. #libs

2,520 views

Hashtags

Објавено 12 фев.

Как правильно проверить атрибуты доступа файла? То есть доступна ли запись в файл или является ли он исполняемым? Для этого в Python есть функция os.access() Проверять так: os.access(path, flag) Функция вернёт bool в зависимости от наличия указанного флага. Всего есть 4 флага проверки: os.F_OK - наличие файла на диске os.R_OK - доступ на чтение os.W_OK - доступ на запись os.X_OK - доступ на исполнение Например, вместо try-except лучше делать так (пример из документации): if os.access("myfile", os.R_OK): with open("myfile") as fp: return fp.read() #basic#libs

2,270 views

Hashtags

Објавено 10 фев.

GUI для Pyinstaller Auto PY to EXE — GUI-обёртка для Pyinstaller! Создаём команду сборки с помощью диалога. Для профессионалов пользы не много, а начинающим будет интересно посмотреть какие есть основные опции у Pyinstaller и как они выглядят в команде. 🎬 Видео урок 📦 Репозиторий ❓FAQ по использованию PS. Пусть вас не смущает слово EXE в названии и Windows в уроке. Эта штука работает и на Linux и на MacOS. #libs

2,340 views

Hashtags

Објавено 8 фев.

Как быстро отрезать от пути несколько элементов с любой стороны? Например, есть длинный путь: path = '/home/user/projects/proj1/assets/assetname/geo/publish/v001/body.geo' Для удобного отображения логов (или еще какой-то абстрактной задачи) я хочу видеть только 3 последних элемента. ▫️Сейчас мы не будем усложнять задачу с выделением только нужных элементов с парсингом самой строки. Работаем только с индексами элементов. ▫️Учитываем, что путь может прийти с неизвестно куда направленными слешами. ▫️Хочу реализацию в одну строку Вот так можно это сделать с помощью модуля os.path >>> os.path.join( ... *os.path.normpath( ... path ... ).replace( ... '\\', '/' ... ).split('/')[-3:]) 'publish/v001/body.geo' Монструозно, но работает👹 Более красивый вариант это класс pathlib.Path. У него есть две функции, которые нам помогут 🔸 Свойство parts, которое возвращает список элементов пути. 🔸 Конструктор Path() может принимать несколько строк которые объединятся в один путь. То есть аналогично функции join. >>> Path('folder', 'file') PosixPath('folder/file') Поэтому мы можем сделать так: >>> Path(*Path(path).parts[-5:]) PosixPath('publish/v001/body.geo') Ну вот, более лаконично (питонично🙄) А еще можно вырезать середину, оставив начало и конец >>> p = Path(path) >>> Path(*p.parts[:3],'...', *p.parts[-2:]) PosixPath('/home/user/.../v001/body.geo') #tricks#libs

2,160 views

Hashtags

Објавено 20 јан.

Как получить минимальную информацию о модули не импортируя сам модуль? Стандартная библиотека pyclbr позволяет это сделать. Она не импортит модуль, а только парсит код и возвращает список имеющихся в модуле классов и функций в виде специальных объектов. Например, вы сможете узнать какие в модуле есть классы, от чего они наследованы и какие у них методы. Возьмём для примера такой простой модуль # mymodule.py class Cls1: def __init__(self): pass def execute(self): pass class Cls2(Cls1): pass def start(): pass Запускаем анализ >>> import pyclbr >>> mdata = pyclbr.readmodule_ex('mymodule') # список всего что нашлось >>> print(mdata) {'Cls1': <pyclbr.Class object at 0x000001B62F9D4288>, 'Cls2': <pyclbr.Class object at 0x000001B62F9DD908>, 'start': <pyclbr.Function object at 0x000001B62F8A8288>} # список методов класса (имя метода и строка объявления) >>> mdata['Cls1'].methods {'__init__': 3, 'execute': 6} # получения наследуемых классов >>> mdata['Cls2'].super [<pyclbr.Class object at 0x000001B62F9D4288>] >>> mdata['Cls2'].super[0].name 'Cls1' #libs#tricks

2,750 views

Hashtags

Објавено 14 дек.

Как разделить строку с shell-командой на отдельные аргументы в виде списка? Если сделать просто сплит по пробелу то получим то что надо, кроме случаев со вставками текста с пробелами. Например так: >>> '-arg "I Am Groot"'.split(' ') ['-arg', '"I', 'Am', 'Groot"'] Чтобы учитывать текст в кавычках как единый аргумент можно воспользоваться функцией shlex.split() Кто читает мой канал давно, уже в курсе. А что делать, если нужно обратное действие? Объединить аргументы из списка в строку и при этом добавить кавычки в аргумент с пробелами. Конечно, если вы используете subprocess то он сам всё разрулит. Но если вам нужна именно команда одной строкой, то можно воспользоваться готовой функцией в том же subprocess. >>> from subprocess import list2cmdline >>> list2cmdline(['-arg', 'I Am Groot']) '-arg "I Am Groot"' Он также позаботится об экранировании уже имеющихся кавычек >>> list2cmdline(['-arg', 'I Am "Groot"']) '-arg "I Am \"Groot\""' А вот так он может "схлопнуть" в команду JSON >>> list2cmdline(['--json', json.dumps({'key': 'value'})]) '--json "{\"key\": \"value\"}"' _______________ Возможно кто-то спросит, а зачем соединять аргументы в строку если subprocess сам это сделает а os.system не наш путь? Мне как-то потребовалось отправлять команду на удалённое выполнение и в API поддерживалось указание команды только строкой. Так что всякое бывает) #libs#basic

1,670 views

Hashtags

12•••45678•••1011
ПретходнаСтраница 6 од 11Следна