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

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

Страница 19 од 32 · 384 објави

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

Делал оптимизацию своей библиотеки кеширования ответов от API. Нужно было выяснить, какие функции заставляют обращаться в API минуя кеш. Мне нужно было видеть полный стек вызова функции запроса в API. Конечно же первое что приходит в голову это traceback.print_stack(). Но мне не нравится его многословное форматирование. Поэтому я решил сделать свой аналог. Делается это совсем не сложно, достаточно посмотреть как работает функция print_stack() и сделать аналогично. Все дополнительные функции уже имеются в модуле traceback. Первым делом достаём фрейм frame = sys._getframe().f_back Теперь преобразуем его в стек вызовов stack = traceback.extract_stack(frame) Теперь у нас есть список инстансов класса FrameSummary в порядке их вызова. Остаётся сделать вывод for item in stack: print(f"{os.path.basename(item.filename)}[{item.lineno}] -> {item.name}") Получается что-то вроде такого __main__.py[123] -> <module> module1.py[456] -> func1 module2.py[789] -> func2 Как можно улучшить? 🔸 Фильтр по имени файла. Удобно при работе через дебагер, например, в Pycharm. Пропускаются ненужные вызовы. 🔸 Выводить передаваемые аргументы. Придется сделать свой extract_stack. 🔸 Добавить цвета Пример реализации здесь. Просто вызовите эту функцию в том месте где требуется увидеть цепочку вызовов. PS. Да, я знаю на сколько это странный способ дебага. Но такой инструмент потребовался под конкретную ситуацию и он справился хорошо. PPS: А теперь суровый хардкод! Всё в одну строку плюс некоторые дополнения в форматировании! (не повторяйте это дома!) print_stack_simple = lambda: print(*[f"{' ' * i}{os.path.basename(item.filename)}[{item.lineno}] -> {item.name}{'()' if not '>' in item.name else ''}" for i, item in enumerate(traceback.extract_stack(sys._getframe().f_back)[:-1])], sep='\n') #tricks

1,260 views

Hashtags

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

Python + bash Если вам часто требуется запускать shell команды из Python-кода, какой способ вы используете? Самый низкоуровневый это функция os.system(), либо os.popen(). Рекомендованный способ это subprocess.call(). Но это всё еще достаточно неудобно. Советую обратить своё внимание на очень крутую библиотеку sh. Что она умеет? 🔸 удобный синтаксис вызова команд как функций # os import os os.system("tar cvf demo.tar ~/") # subprocess import subprocess subprocess.call(['tar', 'cvf', 'demo.tar', '~/']) # sh import sh sh.tar('cvf', 'demo.tar', "~/") 🔸 простое создание функции-алиаса для длинной команды fn = sh.lsof.bake('-i', '-P', '-n') output = sh.grep(fn(), 'LISTEN') в этом примере также задействован пайпинг 🔸 удобный вызов команд от sudo with sh.contrib.sudo: print(ls("/root")) Такой запрос спросит пароль. Чтобы это работало нужно соответствующим способом настроить юзера. А вот вариант с вводом пароля через код. password = "secret" sudo = sh.sudo.bake("-S", _in=password+"\n") print(sudo.ls("/root")) Это не все фишки. Больше интересных примеров смотрите в документации. Специально для Windows💀 юзеров #libs#linux

1,400 views

Hashtags

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

По аналогии с PEP у Django есть DEP. Самый интересный для меня на данный момент на это DEP 0009: Async-capable Django. Он про то, как будет внедряться поддержка аснихронности. Начиная с версии 3 в Django начали появляться асинхронные плюшки. Это всё еще мало чтобы делать асинхронное приложение, но долгий путь начинается с одного маленького шага! Всё должно пройти в несколько этапов и к 4й версии обещают сделать Django асинхронным! Что это даёт разработчикам в случае если весь фреймворк станет поддерживать async? - Ускорение работы web-приложения? Если правильно писать асинхронный код, то да. - Усложнение кода? Возможно, но фреймворк на то и фреймворк, чтобы прятать сложности где-то внутри. Надеюсь код усложнится не сильно, посмотрим... И когда нам этого ожидать? Судя по этой схемкеDjango 4 выйдет в Декабре 2021 года. А это значит, что у вас есть примерно год чтобы научиться понимать асинхронный код, если еще не умеете😁 #django#pep

1,480 views

Hashtags

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

Почему рекомендуют каждый импорт делать на новой строке? Просто так написано в PEP8, скажете вы. Да, это действительно так. Но PEP8 это стилистические рекомендации. Какая практическая польза от такой записи? Несколько раз мои студенты спрашивали зачем писать длинней когда можно короче? Не это ли один из основных принципов в Python? Как мы хотим писать: import os, sys, subprocess Как рекомендуют import os import sys import subprocess Если "нельзя" писать в одну строку, то зачем добавили такую возможность - перечислять имена импорта? Объясняю в два этапа: 🔸Перечисление добавлено для возможности импорта через from, когда из модуля требуется импортнуть несколько имён from os.path import join, expanduser, sep В PEP328 добавили возможность перечисление вставлять в скобки чтобы переносить на новую строку без экранирования символа новой строки Было from os.path import join, expanduser, \ sep, basename, exists Стало from os.path import (join, expanduser, sep, basename, exists) 🔸 Практическая польза от импортов на разных строках заметна когда вы делаете слияние разных веток кода с конфликтами или просто с изменениями. Допустим, есть два варианта кода # file1.py import fnmatch import time import json import uuid #file2.py import fnmatch, time, json, uuid Зачем-то нам потребовалось изменить импорт, вместо uuid импортим sys. Что покажет нам diff? # file1.py -import uuid +import sys # file2.py -import fnmatch, time, json, uuid +import fnmatch, time, json, sys Заметили разницу? Пусть даже для GIT это совершенно не проблема, кодревью будет происходить удобней с точки зрения человека. Да, это объяснение человека, который сам делает кодревью (и регулярно сам же нарушает эту рекомендацию, о чем потом жалеет😭) Есть ли у вас еще доводы в пользу каждого импорта на новой строке? #tricks#pep

1,340 views

Hashtags

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

https://github.com/davvid/wg-python3/blob/guidelines/deliverables/guidelines.rst Гайдлайн по кодингу на Python с учётом версии 2 и 3. Полезно почитать тем, кто всё еще переходит на Python3. #2to3

1,110 views

Hashtags

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

Что быстрей по производительности, оператор "%" или битовый оператор "&"? Мы знаем что битовые операторы работают жутко быстро. Но и простые операторы достаточно оптимизированы. Вот мои тесты на разных платформах (и разном железе, так что смотрим только разницу) 🔸 Windows 10 >>> timeit.timeit('for x in range(1000): x%2', number=100000) 3.8916409015655518 >>> timeit.timeit('for x in range(1000): x&1', number=100000) 2.883111000061035 🔸 Windows 7 VMWare >>> timeit.timeit('for x in range(1000): x%2', number=100000) 4.5197880999999995 >>> timeit.timeit('for x in range(1000): x&1', number=100000) 5.360066200000006 🔸 Ubuntu 16 VPS >>> timeit.timeit('for x in range(1000): x%2', number=100000) 2.355823243036866 >>> timeit.timeit('for x in range(1000): x&1', number=100000) 2.754374884068966 🔸 Debian 10 VMWare >>> timeit.timeit('for x in range(1000): x%2', number=100000) 2.979030784990755 >>> timeit.timeit('for x in range(1000): x&1', number=100000) 3.54338647100667 🔸 Raspbian 10 (наRaspberryPI 4с процессором ARM) >>> timeit.timeit('for x in range(1000): x%2', number=10000) 1.1418334439999995 >>> timeit.timeit('for x in range(1000): x&1', number=10000) 1.4677007579999923 Хм, только на Windows 10 оператор & быстрей чем %. Может это связано с тем что это единственный не виртуальный процессор (кроме ARM на малине)? Не хочу ничего утверждать этой информацией, это просто для заметки. Не так много у меня железа чтобы сделать нормальные тесты и не так много времени чтобы выяснить причину такого поведения.

1,200 views

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

Как проверить является ли число чётным или нечётным? Конечно же оператор "остаток от деления" is_odd = bool(x%2) Если остаток от деления равен 0 то это чётное число, если 1 то нечётное. Но есть еще альтернативный способ, это битовый оператор AND is_odd = bool(x&1) Как это работает? Распечатайте ряд целых чисел в двоичном формате >>> for i in range(0, 7): >>> print(bin(i)) 0b0 0b1 0b10 0b11 0b100 0b101 0b110 Можно заметить, что последние биты чередуются между 0 и 1. А что делает оператор AND (&)? Он возвращает 1 если оба бита числа имеют значение 1. Учитывая, что у числа 1 в двоичном представлении только один бит равен 1, и он последний, то все остальные биты от любого числа всегда будут возвращать 0. Таким образом, делая операцию AND любого числа с числом 1 мы всегда получим либо число 0 либо число 1. Это будет зависеть от последнего бита другого операнда. Выглядит это примерно так >>> 38 & 1 0 00100110 & 00000001 = 00000000 >>> 227 & 1 1 11100011 & 00000001 = 00000001 #tricks

1,250 views

Hashtags

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

Выполните этот код: >>> import __hello__ Hello world! Данный модуль называют пасхалкой в Python, но это не совсем так. Это модуль добавлен для тестирования и демонстрации "заморозки" модулей. # This file exists as a helper for the test.test_frozen module. Вот так можно убедиться что модуль "заморожен": >>> import imp >>>> imp.is_frozen('__hello__') True Исходник этого модуля можно посмотреть здесь У него так же есть модуль-брат __phello__исходник которого здесь >>> import __phello__ >>> print(__phello__.initialized) True >>> from __phello__ import spam >>> print(spam) <module '__phello__.spam' (frozen)> >>> print(__phello__.__loader__) <class '_frozen_importlib.FrozenImporter'> А вот здесь лежит файл который собирает эти модули В данном случае "ЗАМОРОЖЕННЫЙ" означает что модуль вшит непосредственно в библиотеку python3.dll (Windows) или libpython3.so (Linux). #libs

1,140 views

Hashtags

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

Модуль Qt․py это не просто текстовый модуль, его компоненты генерируются на лету в зависимости от ситуации. Поэтому ваша любимая IDE не сможет качественно сообразить автокомплиты под этот модуль. Решение здесь более чем очевидно, надо сделать stubs-файлы. Это файлы с расширением .pyi, описывающие содержимое модуля но не имеющие рабочего кода. Ну что, готовы потратить пару месяцев своей жизни чтобы описать все классы Qt и их методы? 😭 Расслабьтесь, за вас это уже сделали добрые люди. Спасибо Fredrik Averpil ! Качаем здесь ⬇️ https://github.com/fredrikaverpil/Qt.py/tree/stubs/stubs/Qt Не думаю что стоит устанавливать Qt․py из этого репозитория. Он там не обновляется. Так что забираем только файлы .pyi. За актуальность этих файлов тоже не ручаюсь, но большинство методов там имеются. Установка: 🔸 Вариант 1: - находим куда установлен сам модуль Qt․py, это будет одинокий файл который так и называется Qt․py - кидаем директорию рядом с ним (если есть доступ на запись). Должно получиться так: 📁 site-packages\ 📄 Qt.py 📁 Qt\ ... 🔸 Вариант 2 - копируем директорию Qt куда угодно - пробиваем путь к ней в настройках энвайронмента в переменную PATH так, чтобы путь был ДО директории Qt. Закинуть можно и в свою домашнюю директорию. Если скопируете сюда: ~/stubs/Qt То переменную пишем так export PATH=~/stubs:${PATH} После этого IDE должна распарсить stubs-файлы и автокомплиты появятся 😎 #qt#libs#tricks

1,210 views

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

В прошлом посте говоря "Все вызовы теперь одинаковы" я несколько слукавил. Всё-таки есть в этом зоопарке версий некоторая несовместимость вызов которой просто так не унифицировать. Эти моменты вынесены в отдельный модуль QtCompat (compatibility). Там не так много функций но они довольно полезны. Этот модуль содержит унификаци модуля shiboken2, функций loadUi, translate и несколько переименованных функций классов или изменённую сигнатуру аргументов и возвращаемых значений. Это единственное исключение из правила когда вам потребуется где-то изменить свой код кроме импортов и этот код не похож на обычный код PySide2. Например, в PyQt4 и PySide есть метод QHeaderView.setResizeMode Для PyQt5 и PySide2 они были благополучно переименованы в QHeaderView.setSectionResizeMode Чтобы применить этот метод следует использовать такой код from Qt import QtCompath header = self.horizontalHeader() QtCompat.QHeaderView.setSectionResizeMode(header, QtWidgets.QHeaderView.Fixed) Унификация загрузки UI файлов: # PySide2 from PySide2.QtUiTools import QUiLoader loader = QUiLoader() widget = loader.load(ui_file) # PyQt5 from PyQt5 import uic widget = uic.loadUi(ui_file) # Qt.py from Qt import QtCompat widget = QtCompat.loadUi(ui_file) Хорошо что таких моментов не много и их легко запомнить. Полный список можно посмотреть в таблице. #qt#tricks

1,150 views

Hashtags

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

Для тех кто пишет расширения на PyQt/PySide для CG-софтов. Когда я только начинал писать тулзы под Maya (тогда еще версия 2010-2011) мне приходилось ручками ставить PyQt4 под Maya. Даже написал мануалы по установке на своём сайте. Но потом стал доступен из коробки PySide и позже он обновится до PySide2. Для некоторых систем была поддержка PyQt5. И как простому разработчику поддерживать этот зоопарк? Ведь хочется чтобы тул работал на любой версии (вы тоже делали модуль что-то типа import_qt.py?😁) На помощь приходит проект Qt.py который поставил себе цель унифицировать использование Qt-биндингов вне зависимости от среды где запускается код. Те, кто давно пишут на Qt, скорее всего знают этот проект. Он стал стандартом для CG-индустрии и используется в топовых студиях и проектах. Qt․py помогает запускать один и тот же код на разных платформах с разными вариантами Qt-библиотек. Это может быть как интеграция в CG-софт, так и переносимость стендалонов между разными платформами с разными версиями Python. Я решил рассказать о некоторых особенностях работы с этой библиотекой. Сегодня о том, как установить и использовать Qt․py и что это вам даёт. Установка pip install Qt.py Чтобы начать использовать Qt․py в коде достаточно заменить импорт вашего варианта Qt-биндинга на Qt․py from [PySide|PyQt4|PySide2|PyQt5] import QtWidgets => from Qt import QtWidgets Теперь ваш код будет поддерживать любой вариант биндинга Qt в Python. При этом не потребуется использовать if-else конструкции под разные версии. Все вызовы теперь одинаковы. Всё что нужно сделать, это написать его по правилам PySide2. Именно эта версия была взята за основу. Приоритет импорта такой: 1. PySide2 2. PyQt5 3. PySide 4. PyQt4 Что именно загрузилось можно посмотреть в переменной __binding__ >>> import Qt >>> Qt.__binding__ 'PySide2' Приоритет имопрта можно изменить через переменные QT_PREFERRED_BINDING и QT_PREFERRED_BINDING_JSON. Причем под каждый проект оверрайды можно настраивать индивидеально. #qt#libs

1,190 views

Hashtags

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

Метод строки isidentifier() поможет узнать, подходит ли данная строка в качестве имени объекта. Вполне может заменить самостоятельно придуманную регулярку. >>> 'some_name'.isidentifier() True Обычное имя переменной >>> '私は手紙です'.isidentifier() True Юникод в качестве имени тоже доступен >>> '1_name'.isidentifier() False Имя не может начинаться с цифры >>> '੬_name'.isidentifier() False Включая все цифры юникода >>> 'some name'.isidentifier() False Пробелы недопустимы #basic

1,120 views

Hashtags

12•••10•••1718192021•••303132
ПретходнаСтраница 19 од 32Следна