TGINSIGHT CHAT
Python Заметки
@pythonotes
EducationИнтересные заметки и обучающие материалы по Python Контакт: @paulwinex ⚠️ Рекламу на канале не делаю!⚠️ Хештеги для поиска: #tricks #libs #pep #basic #regex #qt #django #2to3 #source #offtop
Неодамнешни објави
Ознака: #libs · 124 објави
Објавено 21 сеп.
Выполнение функции перед выходом. Как вызвать функцию перед выходом из программы в Python? Для этого нужно использовать модуль atexit. Он регистрирует функции, которые выполняются перед завершением процесса интерпретатора. import atexit def before_exit(): print('BEFORE EXIT') atexit.register(before_exit) Теперь попробуйте завершить процесс и увидите сообщение >>> exit() BEFORE EXIT 🔸 Для регистрации такой функции в REPL пригодится startup скрипт. 🔸 Этот функционал работает и в обычном режиме без интерактивной консоли. #tricks#libs
Објавено 16 сеп.
Функция sub в regex может принимать функцию в качестве аргумента repl. 📄 Из документации: If repl is a function, it is called for every non-overlapping occurrence of pattern. The function takes a single match object argument, and returns the replacement string. То есть для каждого совпадения будет вызвана функция для вычисления замены вместо замены на одну и ту же строку для всех совпадений. Иными словами, для замены разных совпадений на разные строки не потребуется запускать re.sub() много раз для каждой строки замены. Достаточно определить функцию, которая вернёт строку для каждого из совпадений. Описание слишком запутанное🤔, давайте лучше рассмотрим на простом примере: Создаем карту замены. То есть какие строки на какие требуется менять. remap = { 'раз': '1', 'два': '2', 'три': '3', 'четыре': '4', 'пять': '5', } Пишем функцию поиска строки для замены. Единственным аргументом будет объект re.Match. Используя данные этого объекта мы вычисляем замену on-the-fly! def get_str(match: re.Match): word = match.group(1) return remap.get(word.lower()) or word Пример текста. text = '''Раз Два Три Четыре Пять Вместе будем мы считать Пять Четыре Три Два Раз Мы считать научим вас ''' Теперь запускаем re.sub и вместо строки замены (repl) подаём имя функции. (Данный паттерн ищет отдельные слова в тексте) >>> print(re.sub(r'(\w+)', get_str, text)) 1 2 3 4 5 Вместе будем мы считать 5 4 3 2 1 Мы считать научим вас Думаю, достаточно наглядно 🤓 #libs#regex
Објавено 14 сеп.
Типы файлов, которые может прочитать Python используя только стандартные библиотеки. Сделал подборку модулей из стандартной библиотеки для чтения/записи различных типов файлов. В данную подборку не вошли такие модули как pickle или zipapp, так как это форматы внутренней кухни Python. Рассматриваем только внешние форматы. ——————————— Module:aifc Type: aiff, aifc Details:Audio Interchange File Format Этот тип аудио файлов используется для записи звука в высоком качестве. Файл AIFC представляет собой сжатую версию формата AIFF. Module: binhex Type: hqx (BinHex4) Details: Кодирование бинарных файлов в шестнадцатеричный текстовый формат и обратно (Binary-to-hexadecimal). Module: bz2 Type: bzip2 Details: Архивация по алгоритму bzip2 Module: chunk Type: aiff/aiff-c, rmff Details: Audio Interchange File Format, Real Media File Format Module: html Type: html Details: Утилиты для работы с форматом HTML Module: json Type: json Details: Поддержка формата JSON. Module: lzma Type: xz, lzma Details: Архивация данных с алгоритмом LZMA и поддержка старого формата XZ Module: msilib Type: msi Details: Создание файлов типа Microsoft Installer, инсталляторы для Windows. Module: sqlite3 Type: sqlite Details: Интерфейс для работы с реляционной базой данных SQLite Module: sunau Type: au Details: Интерфейс для взаимодействия с аудио файлами SunAU Module: tarfile Type: tar Details: Чтение и запись файловых контейнеров в формате TAR, с поддержкой сжатия gzip, bz2 и lzma. Module: wave Type: wav Details: Чтение и запись аудио файлов без сжатия формата WAV. Module: xml Type: xml Details: Интерфейс для манипуляций с текстовым форматом XML. Module: zipfile Type: zip Details: Чтение и запись архивов ZIP. Module: zlib Type: gz Details: Чтение и запись архивов GZ с помощью библиотеки zlib Module: csv Type: csv Details: Comma Separated Values, формат для записи табличных данных. Module: configparser Type: ini Details: Чтение и запись формата конфигов Microsoft Windows INI file Module: netrc Type: netrc Details: Парсинг файлов netrc для хранения данных аутентификации пользователей. ——————————— Надеюсь, кому-то данная информация поможет не изобретать велосипеды))) Напоминаю, что в список попали только стандартные библиотеки которые идут в поставке с Python. #libs
Hashtags
Објавено 4 сеп.
Существуют фреймворки для создания десктоп приложений на базе WebGUI (HTML+CSS+JS). Например Electron, NW.js и другие. Вся логика у них пишется на JavaScript. Если хотите писать такие приложения с логикой на Python, то для вас есть аналог, это библиотека Eel. 🔸 Создавайте десктоп-GUI из HTML страниц со всем доступным для них функционалом. 🔸 Вызывайте Python-функции из JavaScript. 🔸 Вызывайте JavaScript функции из Python. 🔸 Есть встроенный сборщик приложения в Standalone через PyInstaller. Eel запускает сервер и создаёт минималистичный chromium-браузер, который работает с этим сервером. (Вы также можете открыть GUI вашего приложения и в обычном браузере, пока само приложение запущено) Я за полчаса собрал нехитрое приложение, выполняющее Python-код введённый в HTML форме. 🌎https://github.com/paulwinex/eel-webform-example Для десктоп приложений идеально подойдет концепция SPA(Single Page App). Мой элементарный пример на Vue.js 🌎https://github.com/paulwinex/eel-vuejs-example ➡️На почитать #libs
Hashtags
Објавено 2 сеп.
Интересная библиотека tqdm, добавляющая прогресс бар для вашей итерации в CLI скриптах. Что показывает прогресс бар? - прогресс в процентах - прогресс в количестве итераций - потраченное и оставшееся время выполнения - скорость выполнения в итерациях в секунду Использовать очень просто, оберните итератор в tqdm и получите прогресс обработки! from tqdm import tqdm for i in tqdm(iterable_obj): # do something Всё сломается если внутри цикла есть какая-либо печать в stdout #libs
Hashtags
Објавено 24 авг.
Как прочитать файл из ZIP архива не распаковывая этот архив? Недавно была задача достать данные из JSON файла который лежит в ZIP архиве. Первое, что приходит в голову – распечатать архив в TEMP и найти нужный файл. Но с Python можно сделать проще: прочитать нужный файл в архиве не извлекая всё содержимое. Например, есть некий архив archive.zip. Где-то внутри есть файл config.json который нам надо прочитать. Вот код который это сделает: from zipfile import ZipFile from pathlib import Path import json def get_json_from_zip(archive, file_name): zip = ZipFile(archive) for zipname in zip.namelist(): if Path(zipname).name == file_name: with zip.open(zipname) as f: return json.load(f) config_name = 'config.json' archive_path = 'archive.zip' conf = get_json_from_zip(archive_path, config_name) #tricks#libs
Објавено 19 авг.
Думаете что curses крутая библиотека но сложная? Urwid тоже не очень помогает? Тогда посмотрите на высокоуровневую библиотеку py_cui. Это обертка для curses которая предлагает простую схему построения интерфейсов основанную на GridLayout. Он позволяет располагать различные виджеты плиткой, что-то вроде интерфейса Metro. Библиотека реализует простой принцип навигации: 🔸 переключение между плитками: стрелки на клавиатуре В обычном режиме вы можете "гулять" по сетке выбирая нужный виджет. 🔸 активация виджета: Enter В этом режиме вы входите в контекст виджета и можете с ним взаимодействовать 🔸 деактивация виджета: Esc По нажатию на Esc вы возвращаетесь в режим выбора виджета Посмотрите примеры и зацените приложение для работы с GIT. А еще на нем можно простые игры писать. PS. При желании набор символов для рисования границ виджетов можно изменить. #libs
Hashtags
Објавено 12 авг.
Как получить справку в Python имея только консоль? 🔸 Основная справка python3 -h Команда вводится в консоль. Даёт информацию по флагам и переменным интерпретатора. 🔸 Справка по объектам Сначала нужно зайти в REPL (интерактивная консоль Python) и там вводить такой код >>> import some >>> help(some) Функция help() достаёт докстринги и распечатывает в консоль. Это самый очевидный способ получить справку по объекту не выходя из консоли. Но в такой метод нельзя передать директивы, например import или def >>> help(import) SyntaxError: invalid syntax 🔸 модуль pydoc Специальный инструмент для работы с документаций в Python. Доступные команды: как использовать pydoc python3 -m pydoc показать справку по функции или классу python3 -m pydoc os.path.join показать справку по ключевым словамязыка python3 -m pydoc <keyword> например python3 -m pydoc import python3 -m pydoc def справка по модулям python3 -m pydoc <modulename> поиск по документации python3 -m pydoc -k <request> Есть еще одна интересная возможность — запускать веб сервер документации как оболочка для pydoc. То есть это не статичные HTML страницы из файлов, а сгенерированные на лету из докстрингов. запустить веб сервер с документацией на порту 8000 python3 -m pydoc -p 8000 Теперь можете зайти на этот хост по указанному порту и получите простой сайт с документацией. Если вы на локальном хосте, то можно открыть браузер введя команду b, или добавить такой же флаг в команду чтобы браузер открылся сам сразу. Запустить веб сервер и сразу открыть браузер python3 -m pydoc -p 8000 -b ____________________ PS. Чтобы с помощью функции help() получить справку по ключевым словам, следует их писать в виде строки help('import') #libs
Hashtags
Објавено 10 авг.
Все мы любим pathlib за его краткость, логичность и ООП-подход. История его появления в стандартных библиотеках это пример как надо интегрировать новые принципы в архитектуру языка программирования или любого приложения. Расскажу кратко, по этапам: 🔸 Сначала у нас был os.path. Это функциональный подход который выглядит громоздко и многословно. #пример переименования import os my_path = '/path/to/file.ext' dir_name = os.path.dirname(my_path) new_name = 'file2' + os.path.splitext(my_path)[1] new_path = os.path.join(dir_name, new_name) os.rename(my_path, new_path) 🔸 В версии 3.4 появилась библиотека pathlib которая поменяла ход игры. Теперь работаем с путями как с объектами. Кода стало меньше, счастья больше. # пример переименования с pathlib from pathlib import Path my_path = Path('/path/to/file.ext') new_path = my_path.with_name('file2').with_suffix(my_path.suffix) my_path.rename(new_path) 🔸 С приходом этой сущности появились и проблемы, старые методы для работы с путями просто не понимают этот тип. Они работают только со строками. my_path = Path('/path/to/file.ext') open(my_path) TypeError: invalid file: PosixPath('...') То же самое с subprocess и остальными. 🔸Возникла задача адаптации всех стандартных методов для работы с данной библиотекой. Чтобы каждый из них смог понять объект Path и правильно его обработать. И самое интересное, как это было реализовано. 🔸 Если объект Path конвертнуть в строку str(Path) то мы получим правильный путь. Получается, что надо просто добавить форсированную конвертацию аргументов в str везде где это нужно? Нет!, так мы только всё усложим. Просить юзеров конвертить в str когда нужно? Тоже нет, не pythonic-way. В результате в Python 3.6 появляется новый абстрактный класс os.PathLike и понятие path-like object, который понимают все стандартные методы работы с файлами. Теперь, при написании библиотеки для работы с путями, ваша задача следовать правилам этого типа чтобы аккуратно вписаться в экосистему Python-путей. А правила там простые, magic-метод ˍˍfspathˍˍ (file system path), который возвращает валидный путь. Все методы для обработки файлов используют os.fspath() для объекта пути перед его использованием. class MyPath(os.PathLike): def __init__(self, val): self.val = val def __fspath__(self): return self.val path = MyPath('/path/to/file/ext') f = open(path, 'w') # PROFIT!!! Это сработает и без наследования от os.PathLike, Достаточно и только метода ˍˍfspathˍˍ. Но лучше всё же наследоваться, чтобы добавить дополнительные проверки субклассов. А если наследоваться не получается то можно воспользоваться методом register os.PathLike.register(MyPath) Кстати, именно так и поступили в pathlib 🔸Вывод В этой истории показательно то, что вместо внесений изменений под конкретный случай (читай костыль), разработчики создали подходящие условия для всех. То есть не библиотека диктует правила как с ней обходиться, а язык создаёт правила как нужно подстроиться библиотеке чтобы все были довольны. В результате разработчики не только вписали удобную библиотеку в привычный нам код, но и мы получили возможность писать свои альтернативные системы работы с путями, которые понимаются всеми стандартными методами. Это принцип за который я сам всегда всеми руками ЗА. Низкоуровневые решения не должны заниматься частными случаями. Если мы попробуем подстроиться под каждый необычный случай то получим жуткую кашу из if-else, try-except или еще чего похуже. Когда вас просят поправить ваш api, потому что вот тут в таком-то случае у юзера всё ломается, остановитесь на секунду и подумайте, а точно ли вам нужно делать именно то что просят? Если ваше решение начинается с if, это неверное решение! #libs#tricks#pathlib
Објавено 7 авг.
В прошлом посте мы закешировали строки в таблицу “interned strings” И что мы получаем от этого? Прирост скорости достаточно мал и не будет заметен. Экономия памяти уже получше, но реально увидеть различия можно только на больших массивах данных. Где тогда это применять? 🔸Пример 1 Если вы делаете синтаксический разбор большого текста, вполне имеет смысл закинуть в кеш часто встречающиеся части текста. Например, самые популярные слова. Если их наберется несколько миллионов по всему тексту, то уже хорошая экономия памяти. Да, короткие слова Python сам кеширует, но если вы прочитали их из файла то это следует сделать самостоятельно. 🔸Пример 2 В "этих ваших интернетах" часто приводят такой пример: Функция intern() помещает строку в таблицу, либо возвращает ссылку на тот же объект если строка там уже есть. И это может очень пригодится для сравнения больших строк. Ведь оператор "is", проверяющий совпадение адреса в памяти, работает куда быстрей чем оператор "==", сравнивающий все символы в строке. Мы можем закинуть в кеш две строки и просто сравнить их через оператор "is". Синтетический тест сравнения показывает прирост скорости в 50-55 раз. Но так ли часто нам надо сравнивать две большие и одинаковые строки столько раз? Этот тест лишь показывает разницу в скорости операторов и тот факт что intern() действительно делает две переменные одним объектом. Давайте сделаем иначе, вторую строку будем создавать в каждой итерации и сравнивать с эталоном, созданным один раз. И тут мы получаем просадку по скорости в 10 раз😕! Почему? Могу предположить, что intern() для добавления строки в таблицу делает обычное сравнение с другими элементами таблицы, и лишь потом выдаёт результат. То есть, для добавления строки в кеш проверка посимвольно всё равно происходит, но только добавляется еще ряд других операций. В итоге никакой выгоды не получаем. Итого Выходит, что самый модный пример про функцию intern() не очень-то пригоден в работе. Реальный профит мы получим если будем использовать эту функцию аналогично задумке её основному назначению — кеширование часто используемых строк, то есть первый пример. #tricks#libs
Објавено 5 авг.
В прошлом посте мы узнали, что не все строки кешируются интерпретатором в момент создания. Даже если строка короткая но содержит недопустимые символы, она не закешируется. >>> a = '😁' >>> b = '😁' >>> a is b False Но мы можем форсированно закешировать любую строку, обойдя эти правила. Мало ли, вдруг у вас будет словарь где ключ это смайл ))). Для этого просто используйте функцию sys.intern() >>> a = sys.intern('😁') >>> b = sys.intern('😁') >>> a is b True Теперь ваша строка добавлена в таблицу "interned" strings. Да, это успех! Но что то нам даёт? Узнаем в следующем посте. #tricks#libs
Објавено 24 јул.
Что делать если в файле записан текст не ASCII символами? Например кириллица или иероглифы. Вероятно, и кодировка у него будет не utf-8. Попытка прочитать такой файл может завершиться ошибкой: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc4 in position 25: invalid continuation byte Всё просто, используем аргумент encoding при открытии файла >>> f = open(filepath, encoding="windows-1251") А как быть когда кодировка неизвестна? Делать серию try-except перебирая разные варианты? Конечно нет! Можно использовать библиотеку для определение кодировки chardet. >>> import chardet >>> chardet.detect(open(filepath, 'rb').read()) {'encoding': 'windows-1251', 'confidence': 0.9657063861040789, 'language': 'Russian'} Функция detect() принимает байты а не строку. Полный код >>> import chardet >>> filepath = '...' >>> enc = chardet.detect(open(filepath, 'rb').read())['encoding'] >>> text = open(filepath, encoding=enc) #libs
Hashtags