В стандартной библиотеке os есть интересный метод os.nice().
Как написано в документации:
Add increment to the process’s "niceness".
Добавляет "любезности" процессу??? Ну почти...
В Unix системах есть стандартная утилита nice, которая может контролировать приоритет использования CPU процессом.
Обычно это значение 0, что значит стандартный приоритет. Но если добавить "любезности", то процесс будет больше отдавать другим, оставляя себе минимальный приоритет. Или наоборот.
Запустим тест чтобы визуально увидеть разницу.
🔸 Загрузите процессор на 100%.
Можно поставить любую тяжёлую задачу.
Например, сохраните этот код в файл и запустите в консоли (Python3)
🔸 Напишите функцию которая активно использует процессор и считает потраченное время.
🔸 Тестируем
🌎 Код тестов
🔸 Где может пригодиться?
- Повышение приоритета позволит захватывать больше процессорного времени, выполняя важные задачи быстрей.
- Понижение приоритета позволит повысить отзывчивость компьютера во время выполнения тяжёлых расчётов.
🔸 Что еще нужно помнить?
- Чтобы добавить приоритет нужно в функцию os.nice() отправить отрицательное значение. Так как данный метод всегда прибавляет число к текущему приоритету.
- Понижение приоритета доступно любому юзеру, повышение доступно только если процесс запущен от суперюзера.
- Узнать текущее значение:
- работает только на Linux.
- Доступный диапазон значений -20...19.
#libs
Как написано в документации:
Add increment to the process’s "niceness".
Добавляет "любезности" процессу??? Ну почти...
В Unix системах есть стандартная утилита nice, которая может контролировать приоритет использования CPU процессом.
Обычно это значение 0, что значит стандартный приоритет. Но если добавить "любезности", то процесс будет больше отдавать другим, оставляя себе минимальный приоритет. Или наоборот.
Запустим тест чтобы визуально увидеть разницу.
🔸 Загрузите процессор на 100%.
Можно поставить любую тяжёлую задачу.
Например, сохраните этот код в файл и запустите в консоли (Python3)
🔸 Напишите функцию которая активно использует процессор и считает потраченное время.
import timeМоя функция запускает 10 раз некий код и возвращает среднее время.
def compute():
array = []
for i in range(10):
start = time.perf_counter()
for i in range(1000000):
x = 2*2
array.append(time.perf_counter()-start)
return sum(array) / len(array)
🔸 Тестируем
import osВ консоль распечатается время каждого теста и разница времени.
# запускаем первый тест в дефолтным приоритетом
t1 = compute()
# меняем приоритет на минимальный
os.nice(19)
# запускаем второй тест
t2 = compute()
# смотрим реузльтат
print("Test 1", t1, "sec")
print("Test 2", t2, "sec")
print("Diff", t2/t1, "times")
🌎 Код тестов
🔸 Где может пригодиться?
- Повышение приоритета позволит захватывать больше процессорного времени, выполняя важные задачи быстрей.
- Понижение приоритета позволит повысить отзывчивость компьютера во время выполнения тяжёлых расчётов.
🔸 Что еще нужно помнить?
- Чтобы добавить приоритет нужно в функцию os.nice() отправить отрицательное значение. Так как данный метод всегда прибавляет число к текущему приоритету.
- Понижение приоритета доступно любому юзеру, повышение доступно только если процесс запущен от суперюзера.
- Узнать текущее значение:
os.nice(0)
- Запускаемые подпроцессы наследуют приоритет.- работает только на Linux.
- Доступный диапазон значений -20...19.
#libs
Как сохранить картинку непосредственно в Python-модуль?
Для этого нам пригодится библиотека base64.
Этот способ кодирование позволяет любые бинарные или текстовые данные закодировать с помощью 64 ASCII символов. То есть получится простая строка.
Зачем это вообще?
Это обратимое кодирование позволит любые бинарные данные сохранить в текстовом виде и отправить туда где для записи поддерживается только текст.
Например:
- встроить в URL в GET запрос как параметр
- встроить в тело email
- сохранить в Python-модуль как переменную
- сохранить любой конфиг, например JSON
- записать в базу данных
- зашить в HTML (XML) или CSS
Чаще всего так кодируют изображения в HTML и в CSS. Есть даже специальные сервисы для кодирование изображений.
Давайте закодируем и декодируем картинку.
Кодирование:
Декодирование:
Стоит помнить что:
- это не шифрование, пароли так не стоит прятать. Строка легко декодируется в исходник.
- размер данных после кодирования увеличивается примерно на четверть
- не храните изображения в базе данных таким способом!
#libs #tricks
Для этого нам пригодится библиотека base64.
Этот способ кодирование позволяет любые бинарные или текстовые данные закодировать с помощью 64 ASCII символов. То есть получится простая строка.
Зачем это вообще?
Это обратимое кодирование позволит любые бинарные данные сохранить в текстовом виде и отправить туда где для записи поддерживается только текст.
Например:
- встроить в URL в GET запрос как параметр
- встроить в тело email
- сохранить в Python-модуль как переменную
- сохранить любой конфиг, например JSON
- записать в базу данных
- зашить в HTML (XML) или CSS
Чаще всего так кодируют изображения в HTML и в CSS. Есть даже специальные сервисы для кодирование изображений.
Давайте закодируем и декодируем картинку.
Кодирование:
>>> import base64Теперь наша картинка это просто байты в переменной. Её можно сохранить непосредственно в модуле и использовать позже.
>>> src_path = 'image1.png'
>>> with open(src_path, 'rb') as f:
>>> raw_data = f.read()
>>> image_encoded = base64.encodebytes(raw_data)
>>> print(image_encoded)
b'iVBORw...Jggg==\n'
Декодирование:
>>> save_path = "image2.png"Картинка восстановлена обратно в файл.
>>> raw_data = base64.decodebytes(image_encoded)
>>> with open(save_path, 'wb') as f:
>>> f.write(raw_data)
Стоит помнить что:
- это не шифрование, пароли так не стоит прятать. Строка легко декодируется в исходник.
- размер данных после кодирования увеличивается примерно на четверть
- не храните изображения в базе данных таким способом!
#libs #tricks
Ещё немного про base64.
Собрал пример со встроенной в код картинкой. Это иконка для окна на PySide2. Файл кодирован в base64 и просто сохранён в переменной.
Для использования этих данных даже не пришлось сохранять их в новый файл. Иконка создаётся на лету с помощью метода QPixmap.loadFromData()
#libs #tricks #qt
Собрал пример со встроенной в код картинкой. Это иконка для окна на PySide2. Файл кодирован в base64 и просто сохранён в переменной.
Для использования этих данных даже не пришлось сохранять их в новый файл. Иконка создаётся на лету с помощью метода QPixmap.loadFromData()
...
raw_data = base64.decodebytes(ico_encoded)
ico = QPixmap()
ico.loadFromData(raw_data, "PNG")
...
🌎 Полный пример смотрите в gists.#libs #tricks #qt
Наверняка вы слышали о самом простом способе установить PIP, это скрипт get-pip.py. Скачиваем его, скармливаем интерпретатору и PIP установлен!
Если вы сомневались что данный способ хранения данных бывает полезен, то вот вам яркий пример удобного инструмента на его основе. Один простой файл в котором есть всё что ему нужно 😎
#libs
python get-pip.py
Но что это...??? Скрипт размером 1.8 МБ? Я думаю вы уже догадались почему. Смотрим докстринг в начале файла:...
This is a base85 encoding of a zip file, this zip file contains
an entire copy of pip (version ХХ.Х.Х)
...
Да, в скрипте сохранён ZIP архив! Он закодирован с помощью base85 (аналог base64) записан в переменной DATA. Если вы сомневались что данный способ хранения данных бывает полезен, то вот вам яркий пример удобного инструмента на его основе. Один простой файл в котором есть всё что ему нужно 😎
#libs
Как быстро распечатать красиво время имея в наличии число секунд ⏱?
Конечно, можно посчитать сколько в этих секундах минут, часов и потом посчитать остаток, но есть способ быстрей! Это стандартный класс
Конечно, можно посчитать сколько в этих секундах минут, часов и потом посчитать остаток, но есть способ быстрей! Это стандартный класс
datetime.timedelta
Просто создайте класс с указанием того что у вас есть и конвертните его в строку. Он всё посчитает за вас и покажет стандартный формат времени.>>> from datetime import timedelta
>>> str(timedelta(seconds=1024))
'0:17:04'
Можно просто распечатать если результат нужен в консоли>>> print(timedelta(minutes=128))
2:08:18
Также поддерживаются нецелые значения. Например, нецелое число минут будет преобразовано в секунды.>>> print(timedelta(minutes=256.5))Вот так можно распечатать полтора часа
4:16:30
>>> print(timedelta(hours=1.5))Можно выходить за пределы одних суток, появится количество дней
1:30:00
>>> print(timedelta(hours=64.32))
2 days, 16:19:12
>>> print(timedelta(weeks=20.32))
142 days, 5:45:36
А еще они поддерживают математические операции>>> print(timedelta(minutes=5) + timedelta(hours=2))#libs #tricks
2:05:00
Признавайтесь, кто хотел бы написать свой vim из которого можно легко выйти? )))
Это не так сложно как может показаться. По крайней мере движок для интерфейса уже есть в Python из коробки!
Это библиотека curses!
Для Windows она не идет в поставке. Нужно установить windows-curses
Что можно сделать? Вот несколько идей:
🖥 Крутое меню для вашего CLI
📝 Свой текстовый редактор в терминале (vim, nano)
📺 Оконный интерфейс в терминале (Norton Commander, Midnight Commander)
🐍 Игра на базе терминала (тетрис, карты, змейка)
/Каждый питонист должен написать "Змейку"! /
📊 Приложение с анимированными элементами статистики (htop)
🚀 Свой REPL c блекджеком и автокомплитами (bpython, ptpython)
__________________
🌎 Мои эксперементы за вечер, простое меню для выбора действий.
А это мануал на devdungeon.com для тех кто хочет проникнуться этой темой
#libs
Это не так сложно как может показаться. По крайней мере движок для интерфейса уже есть в Python из коробки!
Это библиотека curses!
Для Windows она не идет в поставке. Нужно установить windows-curses
pip install windows-cursesЭта библиотека превращает терминал в "ASCII canvas" и можете "рисовать" в нём с помощью любых символов что пожелаете!
Что можно сделать? Вот несколько идей:
🖥 Крутое меню для вашего CLI
📝 Свой текстовый редактор в терминале (vim, nano)
📺 Оконный интерфейс в терминале (Norton Commander, Midnight Commander)
🐍 Игра на базе терминала (тетрис, карты, змейка)
/Каждый питонист должен написать "Змейку"! /
📊 Приложение с анимированными элементами статистики (htop)
🚀 Свой REPL c блекджеком и автокомплитами (bpython, ptpython)
__________________
🌎 Мои эксперементы за вечер, простое меню для выбора действий.
А это мануал на devdungeon.com для тех кто хочет проникнуться этой темой
#libs
Для тех кто бегло просмотрел материал прошлого поста.
Вы могли не заметить ссылку на крутую библиотеку Urwid!
Это обертка для curses, реализующая интерфейс для создания оконных GUI в терминале 😳!
С этой библиотекой вы оперируете не символами и их атрибутами, а виджетами и лейаутами!
Почти как в PyQt, только для терминала.
При этом с виджетами можно взаимодействовать с помощью мыши.
Посмотрите примеры чтобы иметь представление о возможностях.
🌎 Моё меню из прошлого поста, переделанное на Urwid
Это меню понимает клики мышкой.
#libs
Вы могли не заметить ссылку на крутую библиотеку Urwid!
Это обертка для curses, реализующая интерфейс для создания оконных GUI в терминале 😳!
С этой библиотекой вы оперируете не символами и их атрибутами, а виджетами и лейаутами!
Почти как в PyQt, только для терминала.
При этом с виджетами можно взаимодействовать с помощью мыши.
Посмотрите примеры чтобы иметь представление о возможностях.
🌎 Моё меню из прошлого поста, переделанное на Urwid
Это меню понимает клики мышкой.
#libs
Есть такое понятие как Switch Statement. Это некоторая конструкция в языке программирования предназначенная для множественного ветвления алгоритма.
вот примеры реализаций в разных языках:
JavaScrpt
C++ (или здесь)
C#
Ruby
PHP
Go
Delphi
и даже Pascal
В целом, шаблон такой:
И тут внезапно!!! 23 июня 2020г выходит в свет PEP622
И что мы видим? Планы на Python 3.10 по добавлению Switch Statement! Называется он Structural Pattern Matching, но по сути мы получаем тот же синтаксис что и в Switch Statement.
Пока рано его разбирать, просто подождем...
#pep
вот примеры реализаций в разных языках:
JavaScrpt
C++ (или здесь)
C#
Ruby
PHP
Go
Delphi
и даже Pascal
В целом, шаблон такой:
switch query:А что у нас в Python?
case match1:
...
case match1:
...
if condition1:Вполне рабочий вариант. Но явно отличается от примеров выше.
...
elif condition2:
...
elif condition2:
...
else:
...
И тут внезапно!!! 23 июня 2020г выходит в свет PEP622
И что мы видим? Планы на Python 3.10 по добавлению Switch Statement! Называется он Structural Pattern Matching, но по сути мы получаем тот же синтаксис что и в Switch Statement.
match some_expression:В данный момент статус его еще Draft. Интересно как он еще изменится и доживет ли концепция до релиза? Учитывая что один из автором сам Guido van Rossum, можно сказать что внедрят точно!
case pattern_1:
...
case pattern_2:
...
Пока рано его разбирать, просто подождем...
#pep
This media is not supported in your browser
VIEW IN TELEGRAM
Есть у QLabel есть одна особенность. Её минимальный размер определяется текстом, который в неё записан. Это приводит к тому что длинный текст принудительно увеличивает ширину интерфейса.
В большинстве случаев это выглядит плохо.
Как с этим бороться?
🔸 Обрезать текст заранее, задав лимит по длине строки. В этом случае мы теряем часть визуальной информации. Не всегда угадаешь нужный размер. В разных OS шрифт используется разный.
🔸 Делать перенос строки. Тогда мы получим изменение размера в другую сторону, что тоже поломает интерфейс.
🔸 Переопределить paintEvent() и сделать кастомный рендеринг текста. Можно, но слишком сложно для такой задачи.
Проще всего обрезать текст под текущий размер виджета используя класс QFontMetrics.
Он имеет готовый метод elidedText(), который просто вызываем по событию resizeEvent.
Я также добавил установку ToolTip чтобы всегда можно было увидеть полный текст при наведении курсора.
🌎 Код здесь
#qt #source
В большинстве случаев это выглядит плохо.
Как с этим бороться?
🔸 Обрезать текст заранее, задав лимит по длине строки. В этом случае мы теряем часть визуальной информации. Не всегда угадаешь нужный размер. В разных OS шрифт используется разный.
🔸 Делать перенос строки. Тогда мы получим изменение размера в другую сторону, что тоже поломает интерфейс.
🔸 Переопределить paintEvent() и сделать кастомный рендеринг текста. Можно, но слишком сложно для такой задачи.
Проще всего обрезать текст под текущий размер виджета используя класс QFontMetrics.
Он имеет готовый метод elidedText(), который просто вызываем по событию resizeEvent.
Я также добавил установку ToolTip чтобы всегда можно было увидеть полный текст при наведении курсора.
🌎 Код здесь
#qt #source
Когда-то давно, когда я сел за компьютер примерно третий раз в жизни, я изобрёл... самый быстрый и универсальный конвертор форматов изображений🤓
Схематично он довольно просто (ведь всё гениальное просто):
Если вы пишете какую-то программу работы с изображениями, то порой бывает полезно защититься от таких "гениальных" разработок и однозначно понимать какого типа файл перед вами независимо от его имени. В этом вам поможет стандартная библиотека imghdr.
По умолчанию она понимает следующие форматы:
Вернуть функция должна либо строку с типом формата либо None.
Пример проверки файла с изменённым расширением
Всё станет понятно когда посмотрите исходники этого модуля. Код тестов состоит из 2-3 строк, при этом одна из них это return.
#libs
Схематично он довольно просто (ведь всё гениальное просто):
rename my_image.bmp -> my_image.jpg
Ох уж это наивное IT-детство))) Я действительно думал что победил систему. Если Paint открыл, то значит конвертация прошла успешно! 😭Если вы пишете какую-то программу работы с изображениями, то порой бывает полезно защититься от таких "гениальных" разработок и однозначно понимать какого типа файл перед вами независимо от его имени. В этом вам поможет стандартная библиотека imghdr.
По умолчанию она понимает следующие форматы:
rgb
gif
pbm
pgm
ppm
tiff
rast
xbm
jpeg
bmp
png
webp
exr
Вы всегда можете добавить свой формат. Для этого в список imghdr.tests нужно добавить функцию проверки с определённым набором аргументов: байты и открытый файл. Вернуть функция должна либо строку с типом формата либо None.
Пример проверки файла с изменённым расширением
>>> import imghdr
>>> imghdr.what('image.png')
'jpeg'
Как же происходит проверка? Очевидно, что не на основе расширения файла. Каждый тип файла содержит заранее известный паттерн данных (magic number). Функции проверки просто ищут этот паттерн в бинарных данных файла. Если совпадение есть, то формат определён.Всё станет понятно когда посмотрите исходники этого модуля. Код тестов состоит из 2-3 строк, при этом одна из них это return.
#libs
GitHub
cpython/imghdr.py at main · python/cpython
The Python programming language. Contribute to python/cpython development by creating an account on GitHub.
Аналогично imghdr в Python есть стандартная утилита sndhdr.
Определение форматов аудио файлов!
Тест этой библиотеки возвращает не просто формат в виде строки, а именованный кортеж с дополнительными данными о файле. Например длительность, количество каналов или частота семплирования.
Поддерживаются следующие форматы:
(Только WAV, только хардкор!)
Даже в исходниках есть вопрос без ответа...
#libs
Определение форматов аудио файлов!
Тест этой библиотеки возвращает не просто формат в виде строки, а именованный кортеж с дополнительными данными о файле. Например длительность, количество каналов или частота семплирования.
Поддерживаются следующие форматы:
aifcЭммм... а где же MP3? Где Flac??? Может они не вписываются в концепцию библиотеки по каким-либо признакам? Или это задел на развитие? Программисты не используют MP3?
aiff
au
hcom
sndr
sndt
voc
wav
8svx
sb
ub
ul
(Только WAV, только хардкор!)
Даже в исходниках есть вопрос без ответа...
#libs
Python documentation
sndhdr — Determine type of sound file
Source code: Lib/sndhdr.py The sndhdr provides utility functions which attempt to determine the type of sound data which is in a file. When these functions are able to determine what type of sound ...
Вы прониклись идеей определять тип файла не по расширению из имени а по содержимому (по сигнатуре или по magic number)?
Не хватает стандартных библиотек imghdr и sndhdr?
Тогда специально для вас есть решение — библиотека fleep
Только посмотрите на количество поддерживаемых форматов. Изображения, звук, видео, документы, шрифты, 3D пакеты... На данный момент 104 формата!
Стоит заметить, что:
🔸 автор скорее всего разрабатывал её на Windows 10, стоит хорошо проверить её перед использованием на других платформах.
🔸 добавление новых форматов происходит через обновления JSON файла, но я бы сделал под каждый формат отдельный файл. Просто так удобней расширять список форматов не изменяя исходников.
🔸 Список сигнатур файлов для добавления можно найти в интернете, например на вики: https://ru.wikipedia.org/wiki/Список_сигнатур_файлов
🔸 На хабре есть статья от автора
https://habr.com/ru/post/345822/
PS. Также можете взглянуть на filetype
#libs
Не хватает стандартных библиотек imghdr и sndhdr?
Тогда специально для вас есть решение — библиотека fleep
Только посмотрите на количество поддерживаемых форматов. Изображения, звук, видео, документы, шрифты, 3D пакеты... На данный момент 104 формата!
Стоит заметить, что:
🔸 автор скорее всего разрабатывал её на Windows 10, стоит хорошо проверить её перед использованием на других платформах.
🔸 добавление новых форматов происходит через обновления JSON файла, но я бы сделал под каждый формат отдельный файл. Просто так удобней расширять список форматов не изменяя исходников.
🔸 Список сигнатур файлов для добавления можно найти в интернете, например на вики: https://ru.wikipedia.org/wiki/Список_сигнатур_файлов
🔸 На хабре есть статья от автора
https://habr.com/ru/post/345822/
PS. Также можете взглянуть на filetype
#libs
fleep не поддерживает нужный тип файла? Не нашли подходящую сигнатуру в интернете?
Тогда пробуйте ➡️ puremagic, еще больше типов! Возможно самая актуальная библиотека по данной теме.
Всё ещë нет нужной сигнатуры? Видимо, у вас сложный случай. Остаëтся только найти "магическое число" вашего файла самостоятельно.
Делается это достаточно просто. Нужно посмотреть на файл в шестнадцатеричном представлении. Первые биты файла будут вашим искомым значением.
Для просмотра можно использовать:
🔸 mcedit.
Редактор который идёт в поставке с mc (Linux). Жмем F3 для просмотра и сразу F4 для переключения режима.
🔸 xxd (что это?)
Пример для Linux
Для Windows тот же xxd, который идет в поставке с Git
Теперь проходимся по нескольким файлам этого формата и ищем совпадающие первые биты, которые всегда одинаковы. Нужное число найдено!
#libs #tricks
Тогда пробуйте ➡️ puremagic, еще больше типов! Возможно самая актуальная библиотека по данной теме.
Всё ещë нет нужной сигнатуры? Видимо, у вас сложный случай. Остаëтся только найти "магическое число" вашего файла самостоятельно.
Делается это достаточно просто. Нужно посмотреть на файл в шестнадцатеричном представлении. Первые биты файла будут вашим искомым значением.
Для просмотра можно использовать:
🔸 mcedit.
Редактор который идёт в поставке с mc (Linux). Жмем F3 для просмотра и сразу F4 для переключения режима.
🔸 xxd (что это?)
Пример для Linux
xxd myfile.ext | head
head не даёт прочитать весь файл. Нам нужно лишь начало.Для Windows тот же xxd, который идет в поставке с Git
...\Git\usr\bin\xxd.exe -l 100 myfile.ext
Флаг "l" аналогичен head на LinuxТеперь проходимся по нескольким файлам этого формата и ищем совпадающие первые биты, которые всегда одинаковы. Нужное число найдено!
#libs #tricks
Так что же такое этот Magic Number?
Это набор байтов, уникальный для определённого типа файла. Он еще называется Сигнатура файла.
Не каждый файл имеет магическое число, например текстовые файлы в них не нуждаются.
По этому набору битов можно точно определить какого типа бинарный файл открыт. Если программе очень важно не перепутать тип файла, то она будет определять его именно по сигнатуре, а не по имени файла.
В Python для скомпилированных PYС-файлов магическое число отличается от версии к версии. По нему можно определить версию интерпретатора, которым скомпилирован этот байт-код.
Пример библиотеки для определения версии
Получить magic number текущей версии можно так:
Python 3
Если версия не подходящая вы увидете ошибку:
Итого, сигнатура файла помогает:
🔸 быстро определить формат файла вне зависимости от имени (например для запуска соответствующего приложения в OS)
🔸 обозначать совместимость одного и того же бинарного формата с разными версиями софта (пошло из Unix систем)
🔸 разделить бинарники программ по вариантам сборки
🔸 восстанавливать файлы при потере таблицы файлов диска
🔸 использовать быстрый поиск файлов по типу без обращения к таблице файлов
🔸 получить типа файла, передаваемого по сети, не качая его целиком
Список этим, конечно же, не ограничивается.
#libs #tricks
Это набор байтов, уникальный для определённого типа файла. Он еще называется Сигнатура файла.
Не каждый файл имеет магическое число, например текстовые файлы в них не нуждаются.
По этому набору битов можно точно определить какого типа бинарный файл открыт. Если программе очень важно не перепутать тип файла, то она будет определять его именно по сигнатуре, а не по имени файла.
В Python для скомпилированных PYС-файлов магическое число отличается от версии к версии. По нему можно определить версию интерпретатора, которым скомпилирован этот байт-код.
Пример библиотеки для определения версии
Получить magic number текущей версии можно так:
Python 3
>>> from importlib import util
>>> util.MAGIC_NUMBER.hex()
Python 2>>> import imp
>>> imp.get_magic().encode('hex')
Интерпретатор использует это значение для проверки PYC-файлов перед импортом.Если версия не подходящая вы увидете ошибку:
RuntimeError: Bad magic number in .pyc file
То есть, помимо типа файла, магическое число может также обозначать разные версии одного типа.Итого, сигнатура файла помогает:
🔸 быстро определить формат файла вне зависимости от имени (например для запуска соответствующего приложения в OS)
🔸 обозначать совместимость одного и того же бинарного формата с разными версиями софта (пошло из Unix систем)
🔸 разделить бинарники программ по вариантам сборки
🔸 восстанавливать файлы при потере таблицы файлов диска
🔸 использовать быстрый поиск файлов по типу без обращения к таблице файлов
🔸 получить типа файла, передаваемого по сети, не качая его целиком
Список этим, конечно же, не ограничивается.
#libs #tricks
This media is not supported in your browser
VIEW IN TELEGRAM
Опубликовал для вас один из своих учебных проектов моего курса про PySide2 — LaunchPanel.
Это панель, которая выезжает сверху экрана когда к ней подводишь курсор. Содержит кнопки для запуска любых команд.
🔸 можно добавить любые команды
🔸 одна кнопка может содержать много вариантов одной команды. Доступ к ним через контекстное меню
🔸 панель настраивается через файлы конфига
Но самое главное в этом проекте то, что почти каждая строка задокументирована! 😱
Что используется в проекте?
🔸 стилизация виджетов через StyleSheet
🔸 настройка отображения окна как панели без рамок, заголовка и всего остального
🔸 использование файлов конфига
🔸 HTML текст в виджетах
🔸 анимация свойств виджета (позиция и прозрачность)
🔸 реакция виджета на курсор
🔸 запуск подпроцессов
🌎 Исходники забираем здесь
Смотрите, изучайте, пользуйтесь 😉
#qt #source
Это панель, которая выезжает сверху экрана когда к ней подводишь курсор. Содержит кнопки для запуска любых команд.
🔸 можно добавить любые команды
🔸 одна кнопка может содержать много вариантов одной команды. Доступ к ним через контекстное меню
🔸 панель настраивается через файлы конфига
Но самое главное в этом проекте то, что почти каждая строка задокументирована! 😱
Что используется в проекте?
🔸 стилизация виджетов через StyleSheet
🔸 настройка отображения окна как панели без рамок, заголовка и всего остального
🔸 использование файлов конфига
🔸 HTML текст в виджетах
🔸 анимация свойств виджета (позиция и прозрачность)
🔸 реакция виджета на курсор
🔸 запуск подпроцессов
🌎 Исходники забираем здесь
Смотрите, изучайте, пользуйтесь 😉
#qt #source
Регулярно требуется преобразовать какой-либо текст в максимально совместимый текст для URL, имени файла, имени объекта в каком-то софте и тд. Требования совместимости простые: в тексте должны быть только допустимые символы. Обычно это a-z, 0-9 и "_" или "-". То есть, только прописные буквы латинского алфавита и цифры (как пример).
Допустим, нам нужно название статьи в блоге преобразовать в slug для добавления его в URL этой статьи. Как это лучше всего сделать?
В Django по умолчанию есть готовая функция slugify для таких случаев.
Но я её никогда не использую. Почему? Потому что её недостаточно!
Приведём пример
Так как я часто пишу сайты для русскоязычных пользователей эта проблема весьма актуальна. Я не использую стандартную функцию и всегда пишу свою.
Оригинал я не беру в расчёт и пишу полностью свою функцию. И так, по порядку:
🔸1. Исходный текст:
🔸2. Транслит
Необходимо сделать транслит всех символов в латиницу. Здесь очень выручает библиотека unidecode. Помимо простого транслита кириллицы в латиницу она умеет преобразовывать спец символы и иероглифы в текстовые аналоги.
В нашем случае получаем такое преобразование:
А еще наш код уже поддерживает любой язык, будь то хинди или корейский.
🔸4. Фильтр символов
Unidecode не занимается фильтрацией по недопустимым символам. Это мы делаем в следующем шаге через regex. Просто заменим все символы на "_" если они вне указанного диапазона.
🔸5. Slugify
Осталось удалить лишние символы по краям и сделать нижний регистр
🌎 Полный код в виде функции.
______________
PS. Проверку что в строке остался хоть один допустимый символ я бы вынес в отдельную функцию.
#libs #tricks #django
Допустим, нам нужно название статьи в блоге преобразовать в slug для добавления его в URL этой статьи. Как это лучше всего сделать?
В Django по умолчанию есть готовая функция slugify для таких случаев.
Но я её никогда не использую. Почему? Потому что её недостаточно!
Приведём пример
>>> from django.utils.text import slugify
>>> slugify('This is a Title')
'this-is-a-title'
Пока всё отлично>>> slugify('This is a "Title!"')
'this-is-a-title'
Спец символы удалились, всё хорошо.>>> slugify('Это заголовок статьи')
''
Вот и приехали 😢. Если текст не английский то буквы просто игнорируются. Можно это поправить>>> slugify('Это заголовок статьи', allow_unicode=True)
'это-заголовок-статьи'
Но тогда мы не вписываемся в условие. У нас появилась кириллица в тексте.Так как я часто пишу сайты для русскоязычных пользователей эта проблема весьма актуальна. Я не использую стандартную функцию и всегда пишу свою.
Оригинал я не беру в расчёт и пишу полностью свою функцию. И так, по порядку:
🔸1. Исходный текст:
>>> text = 'Мой заголовок №10 😁!'
Взял специально посложней со специальными символами.🔸2. Транслит
Необходимо сделать транслит всех символов в латиницу. Здесь очень выручает библиотека unidecode. Помимо простого транслита кириллицы в латиницу она умеет преобразовывать спец символы и иероглифы в текстовые аналоги.
from unidecode import unidecode
>>> unidecode("Ñ Σ ® µ ¶ ¼ 月 山")
'N S (r) u P 1/4 Yue Shan'
Очень крутая библиотека, советую👍В нашем случае получаем такое преобразование:
>>> text = unidecode(text)
>>> print(text)
'Moi zagolovok No. 10 !'
Отличный транслит. Смайл просто удалился, хотя я ждал что-то вроде :). Ну и ладно, всë равно невалидные символы. А еще наш код уже поддерживает любой язык, будь то хинди или корейский.
🔸4. Фильтр символов
Unidecode не занимается фильтрацией по недопустимым символам. Это мы делаем в следующем шаге через regex. Просто заменим все символы на "_" если они вне указанного диапазона.
>>> text = re.sub(r'[^a-zA-Z0-9]+', '_', text)
>>> print(text)
'Moi_zagolovok_No_10_'
Символ "+" в паттерне выручает когда несколько недопустимых символов идут рядом. Все они заменяются на один символ "_".🔸5. Slugify
Осталось удалить лишние символы по краям и сделать нижний регистр
>>> text = text.strip('_').lower()
>>> print(text)
'moi_zagolovok_no_10'
Получаем отличный slug! 😎🌎 Полный код в виде функции.
______________
PS. Проверку что в строке остался хоть один допустимый символ я бы вынес в отдельную функцию.
#libs #tricks #django
GitHub
django/django/utils/text.py at main · django/django
The Web framework for perfectionists with deadlines. - django/django
Python позволяет передавать любые объекты в качестве аргументов или возвращаемых значений.
А так как в Python всё объекты то функции и классы тоже входят в этот список.
Но как проверить что нам вернули именно функцию? Не класс, не None и не число и не строку.
(Да, динамическая типизация в Python даёт о себе знать)
Например, у нас есть функция, полученная из вне.
Лучше всего сравнить тип объекта с типом функции. Но как это сделать? Если бы у нас был int, то всё очевидно:
Функции, определяющие что объект это:
#libs
А так как в Python всё объекты то функции и классы тоже входят в этот список.
Но как проверить что нам вернули именно функцию? Не класс, не None и не число и не строку.
(Да, динамическая типизация в Python даёт о себе знать)
Например, у нас есть функция, полученная из вне.
>>> func = some_module.get_function()Надо убедиться что это именно функция. Какие есть варианты? Проверим, вызываемый ли это объект.
>>> hasattr(func, '__call__')Но это ничего не говорит о типе объекта. Вызываемым может быть и класс и генератор и lambda.
True
Лучше всего сравнить тип объекта с типом функции. Но как это сделать? Если бы у нас был int, то всё очевидно:
>>> isinstance(value, int)Но где взять ссылку на тип функции? Можно просто забрать его от любой функции
>>> # создаём пустую функциюКаждый раз нам этого делать не надо. Все нужные типы уже есть в модуле types, созданные именно таким способом. Нам остаётся только сделать сравнение
>>> def f():pass
>>> # сравниваем типы
>>> isinstance(func, type(f))
True
>>> import typesНо есть способ еще проще и понятней, это модуль inspect. Всё тоже самое но завёрнуто красиво.
>>> isinstance(func, types.FunctionType)
True
>>> import inspectПриведу неполный но часто используемый мною список функций этого модуля.
>>> inspect.isfunction(func)
True
Функции, определяющие что объект это:
.isfunction() — функция.isbuiltin() — стандартная функция Python.isclass() — класс (не инстанс класса).isabstract() — абстрактный класс.ismethod() — метод класса.isgenerator() — генератор.ismodule() — модуль#libs
Что делать если в файле записан текст не 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Словарь это очень распространённый тип данных в Python.
Он присутствует буквально в каждом скрипте.
Именованные аргументы (kwargs), атрибуты объекта (ˍˍdictˍˍ), любые неймспейсы и тд.
Одна из основных особенностей словаря была в том, что это неупорядоченное множество. То есть порядок добавления ключей не гарантирует что они сохранятся в той же последовательности. Но всё изменилось в Python3.6. Как это произошло?
Словарь, как часто используемый тип данных, стараются максимально оптимизировать. Про одну из таких оптимизация нам рассказывает PEP468 - Preserving the order of **kwargs in a function.
Хм, причем здесь оптимизация?
Всё начинается с отдельной имплементации Python под названием PyPy. В этой версии интерпретатора сделали довольно хорошую оптимизацию словарю.
Показательно разница описана на этой странице
Если вкратце, то дело вот в чём.
Словарь на стороне С это массив. Каждый элемент это тоже массив из 3х элементов (хеш ключа, ключ и значение).
Раньше, чтобы всякий раз при обновлении словаря не изменять размер массива в С (это затратно по времени), изначально он делался с запасом. Как только массив заполняется, его еще увеличивают с запасом, обычно на 1/3. При этом элементы, еще не занятые данными, заполнялись пустышками (полный пример на странице по ссылке выше)
🔸 Увеличилась скорость поиска и добавления ключей.
🔸 Сократился расход памяти в 3 раза
Python 2.x-3.5
🔸 Как бонус (или как побочный эффект), мы получаем упорядоченность ключей.
То есть одним выстрелом завалили трёх мамонтов!
#pep
Он присутствует буквально в каждом скрипте.
Именованные аргументы (kwargs), атрибуты объекта (ˍˍdictˍˍ), любые неймспейсы и тд.
Одна из основных особенностей словаря была в том, что это неупорядоченное множество. То есть порядок добавления ключей не гарантирует что они сохранятся в той же последовательности. Но всё изменилось в Python3.6. Как это произошло?
Словарь, как часто используемый тип данных, стараются максимально оптимизировать. Про одну из таких оптимизация нам рассказывает PEP468 - Preserving the order of **kwargs in a function.
Хм, причем здесь оптимизация?
Всё начинается с отдельной имплементации Python под названием PyPy. В этой версии интерпретатора сделали довольно хорошую оптимизацию словарю.
Показательно разница описана на этой странице
Если вкратце, то дело вот в чём.
Словарь на стороне С это массив. Каждый элемент это тоже массив из 3х элементов (хеш ключа, ключ и значение).
Раньше, чтобы всякий раз при обновлении словаря не изменять размер массива в С (это затратно по времени), изначально он делался с запасом. Как только массив заполняется, его еще увеличивают с запасом, обычно на 1/3. При этом элементы, еще не занятые данными, заполнялись пустышками (полный пример на странице по ссылке выше)
entries = [
['--', '--', '--'],
[-8522787127447073495, 'barry', 'green'],
['--', '--', '--'],
['--', '--', '--'],
['--', '--', '--'],
[-9092791511155847987, 'timmy', 'red'],
['--', '--', '--'],
[-6480567542315338377, 'guido', 'blue']
]
Перерасход памяти очевиден. И что было предложено? Переделать структуру данных словаря разделив его на данные и индексы.indices = [None, 1, None, None, None, 0, None, 2]
entries = [[-9092791511155847987, 'timmy', 'red'],
[-8522787127447073495, 'barry', 'green'],
[-6480567542315338377, 'guido', 'blue']]
Именно этот принцип повторили в Python 3.6. Что мы получаем в итоге?🔸 Увеличилась скорость поиска и добавления ключей.
🔸 Сократился расход памяти в 3 раза
Python 2.x-3.5
>>> d = {x: x*2 for x in range(100)}
>>> d.ˍˍsizeofˍˍ()
12536
Python 3.6>>> d = {x: x*2 for x in range(100)}
>>> d.ˍˍsizeofˍˍ()
4680
Ведь теперь вместо элемента ['--', '--', '--'] у нас просто None, который, кстати, является одним и тем же объектом где бы он не использовался.🔸 Как бонус (или как побочный эффект), мы получаем упорядоченность ключей.
То есть одним выстрелом завалили трёх мамонтов!
#pep
Python Enhancement Proposals (PEPs)
PEP 468 – Preserving the order of **kwargs in a function. | peps.python.org
The **kwargs syntax in a function definition indicates that the interpreter should collect all keyword arguments that do not correspond to other named parameters. However, Python does not preserved the order in which those collected keyword arguments w...
👍1
В PEP509 описано добавление в структуру данных словаря приватного поля с версией. Что это за версия? Она нужна для ускорения проверки изменений в словаре. Разные механизмы должны следить за целостностью данных (например неймспейса, который суть словарь). Чтобы каждый раз не проверять изменился ли словарь, мы просто можем проверить его версию.
На стороне реализации С в структуру данных словаря добавлена приватная переменная
Как посмотреть версию? Из самого словаря не получится. Есть код в тестах для получения свойства
Чтобы попробовать этот код достаточно повторить то что написано в тестах.
Для Windows следует добавить директорию Lib\test в PYTHONPATH.
Жаль только нет стандартного способа получения версии (или я не нашел?). Я думаю применение нашлось бы)
#pep #tricks
На стороне реализации С в структуру данных словаря добавлена приватная переменная
ma_version_tag, которая изменяется всякий раз при изменении словаря.clear()Если вызван один из этих методов, то версия изменяется. Версия это не хеш и не ID. Каждый словарь имеет свою уникальную версию, даже два одинаковых или два пустых словаря.
pop(key)
popitem()
setdefault(key, value)
__delitem__(key)
__setitem__(key, value)
update(...)
Как посмотреть версию? Из самого словаря не получится. Есть код в тестах для получения свойства
ma_version_tag, используется для прогонки тестов. Чтобы попробовать этот код достаточно повторить то что написано в тестах.
Для Windows следует добавить директорию Lib\test в PYTHONPATH.
>>> import _testcapiИнтересно то, что версия изменится даже если данные будут одинаковыми. Главное сам факт изменения.
>>> d1 = {}
>>> d2 = {}
>>> _testcapi.dict_get_version(d1)
12083
>>> _testcapi.dict_get_version(d2)
12099
>>> d = {1:2}
>>> _testcapi.dict_get_version(d)
12200
>>> d[1] = 2
>>> _testcapi.dict_get_version(d)
12239
Таким образом мы можем узнать а не пытался ли кто-то что-либо сделать с нашим словариком? Жаль только нет стандартного способа получения версии (или я не нашел?). Я думаю применение нашлось бы)
#pep #tricks
Python.org
PEP 509 -- Add a private version to dict
The official home of the Python Programming Language