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Број на индексирани објави
Неодамнешен опфат30,109Збир на неодамнешни прегледи
Неодамнешни објави

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

Ознака: #tricks · 178 објави

当前筛选 #tricks清除筛选

Функция subprocess.check_output() удобна, когда нужно просто получить аутпут процесса. info = subprocess.check_output(cmd, text=True) Но вы не сможете таким образом получить аутпут процесса который завершился с ненулевым кодом выхода. Вместо этого у вас выбрасывается исключение CalledProcessError: Command '[...]' returned non-zero exit status 1. Не так давно я столкнулся с этой ситуацией, когда процесс, будучи запущенным с флагом --help, вполне штатно печатает в аут нужную информацию но выходит с кодом 1. И это для него нормальное поведение. За генерацию исключения отвечает аргумент check, который по умолчанию равен False но именно в check_output он равен True и не может быть переопределён при вызове. Нет, это не недосмотр разрабочтков и вам не потребуется искать обходные пути. Дело в том, что вся полезная нагрузка в таких случаях находится в классе исключения. Классы TimeoutExpired и CalledProcessError имеют ряд атрибутов, которые хранят всю нужну инфу. Например, вызванная команда (cmd), код выхода (returncode) и то что мы ищем - аутпут процесса (output) Итого, базовая фукнция для захвата аутпута для любого кода выхода будет выглядеть как-то так: def get_proc_output(cmd): try: return subprocess.check_output(cmd, text=True) except subprocess.CalledProcessError as e: return e.output #tricks

1,890 views

Hashtags

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

Когда пишешь асинхронный код нужно учитывать особенности такого подхода. Всегда требуется держать в уме, когда возвращается корутина а когда реальный результат. Между этими двумя сущностями должен быть вызов через await. Вот пример синхронного запроса в базу данных с помощь sqlalchemy. Query пишу инлайном для компактности. entities = session.execute(select(EntityModel)).scalars().all() Всё ясно и линейно. А вот он же асинхронный. result = await session.execute(select(EntityModel)) entities = result.scalars().all() Это значит что session.execute возвращает корутину, или awaitable объект. Сначала его нужно выполнить через await, тогда получишь объект с которым можно дальше работать. Не хочу сказать что это мастхэв практика, но простые асинхронные запросы тоже можно сократить до одной строки. Просто использовать скобки. entities = ( await session.execute(select(EntityModel)) ).scalars().all() На самом деле я использую такую конструкцию только в прототипах тестов или вспомогательных функциях тестов. В продакшн такое обычно не попадает. #tricks

2,120 views

Hashtags

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

Варианты распаковки контейнеров по отдельным переменным Обычная распаковка по точному количеству data = [1, 2, 3, 4, 5] v1, v2, v3, v4, v5 = data Распаковка с неизвестным количество но не меньше чем N v1, *_ = data v1, *_, v4, v5 = data Если точно знаете позицию нужного объекта в списке, включая вложенные списки, то достать его можно двумя способами Через индекс: data = [[1]] v1 = data[0][0] Через распаковку со скобками: data = [[1]] (v1, ), = data data = [[[1]]] ((v1,), ), = data Еще примеры распаковки вложенных объектов data = [[1, 2], [3, 4], [5, 6]] (v1, v2), (v3, v4), (v5, v6) = data (v1, v2), *_, (v5, *_) = data #tricks

2,009 views

Hashtags

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

Что позволяет делать f-strings в 3.12. ▫️можно использовать одинаковые кавычки во всём выражении ▫️можно добавлять переносы для многострочного выражения ▫️можно использовать символ новой строки (эта проблема неактуальна) >>> print(f"{"\n".join( >>> ["1","2","3", >>> f"{ >>> f"{2+2}" >>> *(2+2) >>> }" >>> ] >>> )}") 1 2 3 4444 #tricks#libs

1,910 views

Hashtags

Објавено 9 окт.

Функция dir() - удобна для получения списка атрибутов у любого объекта. Ранее я писал про функцию __dir__() в модуле (не путайте её с переменной __all__(), которая указывает список объектов для импорта если встречается конструкция from module import *). Скорее всего вы уже знаете как использовать функцию dir(). Любой объект может реализовать метод __dir__() чтобы указать список имеющийхся и динамических атрибутов. И функция dir() поможет получить список этих атрибутов. >>> dir(str) ['__add__', '__class__', '__contains__', ...] У этой функции есть еще один способ применения. Её можно вызвать без аргумента, и в таком случае она вернёт список имён в текущем неймспейсе. >>> dir() ['__builtins__', '__doc__', '__file__', ...] >>> def test(): >>> x = 1 >>> print(dir()) >>> test() ['x'] #basic#tricks

2,140 views

Објавено 3 окт.

Как проверить является ли директория пустой? Самый простой способ: if os.listdir(path): ... Тоже самое с pathlib p = Path(path) if list(p.iterdir()): ... В первом случае функция os.listdir возвращает полный список файлов. Нам остаётся проверить есть ли там что-либо. Во втором случае мы получаем генератор, который под капотом использует тот же listdir. Теперь представим что в директории 10к файлов for i in range(10000): Path(f'/tmp/test/test{i}.txt').touch() Не сказать, что при наличии SSD это проблема, но когда таких операций много, мы начинаем терять время, особенно с pathlib. import timeit test_path = '/tmp/test' count = 1000 >>> timeit.timeit('list(os.listdir(p))', setup=f'import os;p="{test_path}"', number=count) 2.281363710993901 >>> timeit.timeit('list(p.iterdir())', setup=f'from pathlib import Path;p=Path("{test_path}")', number=count) 5.6957218300012755 То есть мы получаем список всех 10к файлов просто чтобы узнать что там есть файлы. Хотя нам надо узнать есть ли по указанному пути хотя бы один файл. Для того чтобы ускорить проверку лучше воспользоваться функцией os.scandir(). Она работает на много быстрей и возвращает итератор с объектами os.DirEntry. Чтобы узнать есть ли в директории хоть один файл достаточно использовать функцию next() next(os.scandir(path)) Но если директория пустая, то мы получим ошибку. Поэтому добавляем значение по умолчанию и можно использовать конструкцию в условном операторе if next(os.scandir(path), None): ... Либо используем функцию any(), так как она завершится сразу после нахождения первого файла или если итератор пуст. if any(os.scandir(path)): ... Сравним скорость >>> timeit.timeit('next(os.scandir(p), None)', setup=f'import os;p="{test_path}"', number=count) 0.2183076049986994 >>> timeit.timeit('any(os.scandir(p))', setup=f'import os;p="{test_path}"', number=count) 0.21016486900043674 #tricks

1,910 views

Hashtags

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

SQLAlchemy - это один из самых популярных ORM для работы с базами данных из Python. - поддерживат все популярные базы данных - не привязана к какому-либо фреймворку (как, например, Django ORM) - поддерживает асинхрон - позволяет удобно (питонично) делать довольно сложные SQL запросы 15 июля вышла первая версия из ветки 2.0 и это хорошйи повод изучить эту библиотеку если еще не начали. Подобрал вам ресурсы для изучения: - Вебинар и урок про новую SQLAlchemy2.0 от Mike Bayer (автор sqlalchemy и alembic ) с онлайн конференции pythonwebconf: https://www.youtube.com/watch?v=Uym2DHnUEno - Для тех кто на английском не очень, есть онлайн книга на руссом от https://t.me/massonnn_yt. А так же видео версия: https://www.youtube.com/watch?v=leeC0fpAY-E&list=PLN0sMOjX-lm5Pz5EeX1rb3yilzMNT6qLM Лично я использую алхимию в связке с FastAPI и пока всё устраивает #tricks#libs

3,260 views

Hashtags

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

У тех, кто часто работает в терминале, есть привычка вызова особо часто используемых команд. например cd, ls, mc... Вместо команды exit можно использовать Ctrl+D, и это удобно. И так уж вышло, что эта привычка невольно у меня включается и при работе в REPL. Для быстрого выхода я жму Ctrl+D, и это работает, но только в Linux. В Windows это совсем не работает, так как там надо нажимать Ctrl+Z. И был бы Windows не такой mustdie если бы этого хватило, но требуется еще нажать Enter (если знаете быстрый выход из REPL на винде, то подсказывайте, я не WinUser). Иногда мне быстрей и привычней вбить exit и нажать Enter, как в bash, но и тут подстава - еще нужны скобки вызова🤬. В общем, настолько высосанную из пальца проблему надо еще поискать 😆, но я нашел для неё решение! q = type('q', (object,), {'__repr__': lambda *args: exit()})() Этот код вставляется в стартап скрипт REPL и создаёт новый объект q. Теперь для выхода из REPL достаточно написать символ q и нажать Enter. Работает одинаково на Linux и Windows. Как это работает? ▫️ динамически создаётся новый тип объекта с помощью конструкции type(NAME, (BASETYPES,), {ATTRS,}) ▫️ в атрибутах создаётся оверрайд метода __repr__, который отвечает за распечатку объекта в REPL ▫️ в этом методе вызывается команда exit() То есть команда выхода срабатывает как только вы пытаетесь распечатать этот объект в консоли. Именно отображение его репрезентации как объекта а не через не print(), который использует метод __str__. Аналогично работающий код выглядит так: class Q: def __repr__(self): exit() q = Q() Из минусов можно выделить следующее: ▫️ имя q занято, но никто не мешает сделать что-то более уникальное ▫️ Нужно как-то добавлять это в стартап. Тут нам поможет startup script Аналогичным способом можно сделать и другие действия, но стоит помнить что это нестандартное поведение в Python, в прод не оставляйте! Пару раз я вставлял аналогичные объекты в интерактивную консоль для дебага, они там выполняли роль шорткатов для каких-то наборов действий PS. Не очень-то это похоже на трик или лайфхак. Это скорей демонстрация гибкости языка в решении надуманных нестандартных проблем. #tricks

3,240 views

Hashtags

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

Как получить путь к файлу текущего класса если метод получения пути находится в родительском классе в другом файле? Например, представим такую ситуацию: # module1.py ### class BaseCls: @classmethod def get_path(cls): print(__file__) # module2.py ### from module1 import BaseCls class MainCls(BaseCls): pass Что покажет код: import module2 module2.MainCls.get_path() Мы ожидаем что путь будет к файлу module2.py, но переменная __file__ объявлена внутри файла module1.py и поэтому будет указывать именно на него. Чтобы получить правильный путь нам следует: ▫️ получить имя модуля текущего класса module_name = module2.MainCls.__module__ ▫️ найти этот модуль в списке импортированных модулей mod = sys.modules[module_name] ▫️ получить значение переменной __file__ filepath = mod. __file__ Вся эта процедура, причём для любого типа объекта, есть в функции inspect.getfile(). Так что наш метод должен выглядеть так: # module1.py import inspect class BaseCls: @classmethod def get_path(cls): print(inspect.getfile(cls)) Теперь из вызов этого метода из класса MainCls найдёт путь к файлу module2.py #tricks

3,430 views

Hashtags

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

Как не передавать аргумент в функцию если она его не ждёт? Как-то раз я делал модуль с функциями, которые вызывались как фоновые задачи. В основном они принимали чёткий список позиционных аргументов. И вот, в разгар разработки, пришла новая фича - в каждую такую функцию теперь передаётся Lock-объект. Он позволяет сделать выполнение этой функции синхронным на разных воркерах (как и положено любому локеру). Но вот проблема, в новых функциях, где нужен локер, я его, конечно же, принимаю как аргумент. Но в старых функциях он не предусмотрен. Часто функции вообще без аргументов. Какие варианты решения? ▫️ Добавить во всех функциях в аргументы **kwargs. Это решит все проблемы. Строго говоря, это надо было сделать сразу. Теперь таски не будут падать из-за неизвестного аргумента. И теперь следует не забывать добавлять **kwargs в новых функциях. Но что, если нет возможности изменять код? Тогда... ▫️Проверить, может ли функция принять аргумент с определённым именем. И если не может то не передавать. Это можно сделать с помощью стандартной функции inspect.signature from inspect import signature def func(x, y, z=True): pass sig = signature(func) print(sig) # <Signature (x, y, z=True)> print(sig.parameters) mappingproxy(OrderedDict([('x', <Parameter "x">), ('y', <Parameter "y">), ('z', <Parameter "z=True">)])) Теперь можно проверить, ожидает ли функция параметр с определённым именем print('lock' in sig.parameters) # False Финальный псевдокод from tasks import my_task, LockClass from inspect import signature task_kwargs = {} lock = LockClass() if 'lock' in signature(my_task).parameters: task_kwargs['lock'] = lock my_task(**task_kwargs) Конечно же, наличие этого имени не гарантирует что функция ожидает именно этот тип. Но это уже нюансы реализации 😼 #tricks

2,650 views

Hashtags

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

Метод строки split() разделяет строку на несколько строк по указанному символу >>> "a_b_c".split('_') ['a', 'b', 'c'] Можно указать максимальное количество разделений >>> "a_b_c".split('_', 1) ['a', 'b_c'] Или резать с другой стороны с помощью rsplit() (right split) >>> "a_b_c".rsplit('_', 1) ['a_b', 'c'] А что будет если оставить аргументы пустыми? >>> "a_b_c".split() ['a_b_c'] Получаем список с одним элементом, потому что по умолчанию используется пробельный символ. >>> "a b c".split() ['a', 'b', 'c'] То есть это равнозначно такому вызову? >>> "a b c".split(" ") ['a', 'b', 'c'] Кажется да, но нет! Давайте попробуем добавить пробелов между буквами >>> "a b c".split(" ") ['a', '', '', 'b', '', '', 'c'] И вот картина уже не так предсказуема 😕 А вот что будет по умолчанию >>> "a b c".split() ['a', 'b', 'c'] Всё снова красиво! 🤩 По умолчанию в качестве разделителя используется любой пробельный символ, будь то табуляция или новая строка. Включая несколько таких символов идущих подряд. А также игнорируются пробельные символы по краям строки. >>> "a\t b\n c ".split() ['a', 'b', 'c'] Аналогичный способ можно собрать с помощью регулярного выражения. Но пробелы по краям строки придется обрабатывать дополнительно. >>> import re >>> re.split(r"\s+", ' a b c '.strip()) ['a', 'b', 'c'] Здесь тоже можно указать количество разделений >>> re.split(r"\s+", 'a b c', 1) ['a', 'b c'] А что если мы хотим написать красиво, то есть split() без аргументов, но при этом указать количество разделений? В этом случае первым аргументом передаём None >>> "a\n b c".split(None, 1) ['a', 'b c'] Данный метод не учитывает строки с пробелами, взятые в кавычки 'a "b c" '.split() ['a', '"b', 'c"'] Но для таких случаев есть другие способы. #tricks#basic

2,930 views

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

Синтаксис f-string позволяет использовать в строке символ обратного слеша "\" но не позволяет использовать его внутри фигурных скобок. >>> lines = ['line1','line2'] >>> print(f'ITEMS: \n {"\n".join(lines)}') SyntaxError: f-string expression part cannot include a backslash Решения: ▫️ вынести этот символ за скобки n = '\n' print(f'ITEMS: \n{n.join(lines)}') ▫️ заменить его на другое представление, например создавать нужный символ с помощью функции chr() print(f'ITEMS: \n{chr(10).join(lines)}') Чтобы узнать код символа следует использовать функцию ord() >>> ord('\n') 10 А с юникодом не выйдет, там тоже слеш >>> print(f'ITEMS: \n{"\u000a".join(lines)}') SyntaxError: f-string expression part cannot include a backslash #tricks

2,620 views

Hashtags

12345•••10•••1415
ПретходнаСтраница 3 од 15Следна