А вы ждёте выхода Python 4? Ну зря ждёте😭
По словам Гвидо, ему хватило проблем с переходом со 2го на 3й)
Лучше постепенно развивать имеющийся функционал с полной совместимостью кодовой базы чем делать такие резкие изменения.
Велика вероятность что выше 3 мажорная версия более не поднимется.
А как же обещания про невероятные ускорения в Python 4? Очевидно, что теперь они все будут добавляться в 3ю ветку.
Вот здесь можно почитать про планы ускорения
где Гвидо обещает скорость 2х уже в 3.11 и х5 через 4 года!
Здесь можно посмотреть следующие шаги по оптимизации.
#offtop #2to3
По словам Гвидо, ему хватило проблем с переходом со 2го на 3й)
Лучше постепенно развивать имеющийся функционал с полной совместимостью кодовой базы чем делать такие резкие изменения.
Велика вероятность что выше 3 мажорная версия более не поднимется.
А как же обещания про невероятные ускорения в Python 4? Очевидно, что теперь они все будут добавляться в 3ю ветку.
Вот здесь можно почитать про планы ускорения
где Гвидо обещает скорость 2х уже в 3.11 и х5 через 4 года!
Здесь можно посмотреть следующие шаги по оптимизации.
#offtop #2to3
TechRepublic
Programming languages: Why Python 4.0 might never arrive, according to its creator
In a Q&A, Python programming language creator Guido van Rossum said it was "almost taboo to talk about a Python 4 in a serious sense" following the troubled migration from Python 2.0 to Python 3.0.
У Python есть очень удобная штука - стек вызовов.
Благодаря нему модуль traceback может показать где и что сломалось в момент выброса исключений.
Но иногда Python просто падает без какой-либо информации. Лично меня это регулярно настигает на Windows и очень бесит. Совершенно не понятно что где произошло и как искать причину. Ставить сишные дебаггеры?
Чтобы быстро понять в какой строке ошибка иногда достаточно использовать встроенный модуль faulthandler
Базовое использование очень простое:
Попробуйте уронить Python без faulthandler и с ним.
#libs #tricks
Благодаря нему модуль traceback может показать где и что сломалось в момент выброса исключений.
Но иногда Python просто падает без какой-либо информации. Лично меня это регулярно настигает на Windows и очень бесит. Совершенно не понятно что где произошло и как искать причину. Ставить сишные дебаггеры?
Чтобы быстро понять в какой строке ошибка иногда достаточно использовать встроенный модуль faulthandler
Базовое использование очень простое:
python.exe -q -X faulthandler main.pyЕсли интерпретатор упадёт, то вы хотя бы узнаете какая строчка привела к такому событию.
Попробуйте уронить Python без faulthandler и с ним.
#libs #tricks
Сегодня на Github закрывается доступ к git-операциям по паролю. Теперь доступ только по токену.
Для входа на сайт следует настроить двухфакторку.
#offtop
Для входа на сайт следует настроить двухфакторку.
#offtop
The GitHub Blog
Git password authentication is shutting down - GitHub Changelog
As previously announced, starting on August 13, 2021, at 09:00 PST, we will no longer accept account passwords when authenticating Git operations on GitHub.com. Instead, token-based authentication (for example, personal…
Как получить значение прав доступа к файлу в виде привычного формата записи 755 или 644?
В целом, способ вот такой:
До того как мы сделали split() строка была следующего вида:
Для этого последние 3 значения ставим максимальными, остальные нулевыми.
Остаётся преобразовать в восьмеричное представление и убрать префикс
Хранить и использовать их удобно в виде восьмеричного int
#tricks
В целом, способ вот такой:
>>> path = '...'Теперь разберёмся что всё это значит.
>>> print(oct(os.stat(path).st_mode & 0o777).split('o')[-1])
'755'
До того как мы сделали split() строка была следующего вида:
0o755
Что это за тип данных? Это тип int в восмиричной системе исчисления. Для преобразования в такой формат есть builtin функция oct()>>> oct(493)Как видите, результат возвращается виде строки. Но это не мешает нам создавать переменные синтаксисом восьмеричных чисел, то есть с префиксом 0o. Хотя, при распечатке мы всё равно получим int.
'0o755'
>>> x = 0o777Преобразовать эту строку в int можно функцией int(), указав базис 8
>>> print(x)
511
>>> int('0o755', 8)
493
Теперь посмотрим что нам возвращает os.stat>>> perm = os.stat(path).st_modeПреобразуем в oct
33261
>>> oct(perm)Уже почти то что надо. Чтобы оставить только нужное, отрезаем лишнее с помощью оператора & (AND).
'0o100755'
Для этого последние 3 значения ставим максимальными, остальные нулевыми.
>>> perm & 0o777Оператор работает с бинарным представлением чисел, то есть операция была вот такая:
493
0b100000111101101Вспоминаем побитовые операторы
& 0b111111111
= 0b111101101
Остаётся преобразовать в восьмеричное представление и убрать префикс
>>> oct(493)Именно в таком виде пермишены файла в коде обычно не используются.
'0o755'
>>> oct(493).split('o')[-1]
'755'
Хранить и использовать их удобно в виде восьмеричного int
os.chmod(path, 0o755)или строки
os.chmod(path, int('0o755', 8))
А зачем в строке если достаточно в int? Наприрмер чтобы в json была удобочитаемая запись. Так как сериализатор запишет восьмеричное число как обычный десятичный int>>> json.dumps(0o755)Поэтому для удобства пишем его строкой а потом преобразуем в восьмеричный int.
'493'
#tricks
Что-то вы гоните насчет "привычного вида формата 755 и 644". Я вот вообще не понял что это! 😳
Действительно, что означают цифры которые мы получили в прошлом посте?
Это кодировка, заключающая в себе режимы доступа к файлу.
Подробней можно почитать в статье про chmod.
Там можно увидеть альтернативное обозначение того же самого с помощью символов
Чтобы преобразовать восьмеричное число в такое обозначение в Python есть готовая функция
А что за знак вопроса в начале?
Давайте передадим в эту функцию необрезанное значение от os.stat
Первый символ обозначает тип объекта. Это может быть файл (
Вот простая схема данной кодировки
Если вы попробуете получить пермишены для симлинка то получите пермишены для файла
Действительно, что означают цифры которые мы получили в прошлом посте?
Это кодировка, заключающая в себе режимы доступа к файлу.
Подробней можно почитать в статье про chmod.
Там можно увидеть альтернативное обозначение того же самого с помощью символов
r w x, что значит чтение, запись, исполнение.Чтобы преобразовать восьмеричное число в такое обозначение в Python есть готовая функция
>>> stat.filemode(0o755)
'?rwxr-xr-x'
Мы видим 3 группы по 3 символа, дающие 3 типа доступа для 3 типов юзеров.А что за знак вопроса в начале?
Давайте передадим в эту функцию необрезанное значение от os.stat
>>> stat.filemode(os.stat(path).st_mode)
'drwxr-xr-x'
Это данные, которые мы безжалостно обрезали в прошлый раз😼Первый символ обозначает тип объекта. Это может быть файл (
-), директория (d) или симлинк (l).Вот простая схема данной кодировки
[1][3][3][3]
│ │ │ │
│ │ │ └──> Others Permissions
│ │ └─────> Group Permissions
│ └────────> Owner Permissions
└───────────> File Type
(разверните экран если вы с телефона)Если вы попробуете получить пермишены для симлинка то получите пермишены для файла
>>> path = '.venv/bin/python3'
>>> stat.filemode(os.stat(path).st_mode)
'-rwxr-xr-x'
Чтобы получить свойства именно симлинка, нужно это явно указать>>> stat.filemode(os.stat(path, follow_symlinks=False).st_mode)
'lrwxrwxrwx'
#tricks #basicКакой тип данных выбрать для оптимального хранения информации? Имеется в виду объем занимаемой памяти.
Можем создать 4 разных варианта объектов и сравнить сколько они занимают оперативки.
Будем создавать простой класс, класс со слотами, именованный кортеж и словарь.
Дело в том, что функция sys.getsizeof() показывает не совсем то что мы ожидаем.
Она берет результат метода
А еще он не гарантирует точность размера типов для third-party расширений.
Для точного измерения размера лучше использовать модуль pympler. Помимо данных он считает сколько места занимает вся структура классов и другая обвязка объекта.
А словарь в этом тесте оказался самый расточительный.
#tricks #libs
Можем создать 4 разных варианта объектов и сравнить сколько они занимают оперативки.
Будем создавать простой класс, класс со слотами, именованный кортеж и словарь.
from collections import namedtuple
from sys import getsizeof
NT = namedtuple('NT', 'v1 v2 v3')
class CLASS:
def init(self, x1, x2, x3):
self.v1 = x1
self.v2 = x2
self.v3 = x3
class SLOTS:
slots = ['x1', 'x2', 'x3']
def init(self, x1, x2, x3):
self.x1 = x1
self.x2 = x2
self.x3 = x3
d = dict(x1=1, x2=2, x3=3)
c = CLASS(1, 2, 3)
s = SLOTS(1, 2, 3)
t = NT(1, 2, 3)
Теперь распечатаем что там по памятиprint(' CLS\t\tSLT\t\tDCT\t\tTPL')
print(f'System: {getsizeof(c)}\t\t'
f'{getsizeof(s)}\t\t'
f'{getsizeof(d)}\t\t'
f'{getsizeof(t)}'
)
CLS SLT DCT TPL
System: 48 56 232 64
Хм, в этой статистике обычный класс самый экономный! Но что-то здесь не так. Неужели он экономичней класса со слотами, который рассчитан на скорость и оптимизацию?Дело в том, что функция sys.getsizeof() показывает не совсем то что мы ожидаем.
Она берет результат метода
__sizeof__ у объекта и добавляет кое-чего от gc.__sizeof__ возвращает размер, занимаемый данными. Но не учитывает размер обвязки этих данных.А еще он не гарантирует точность размера типов для third-party расширений.
Для точного измерения размера лучше использовать модуль pympler. Помимо данных он считает сколько места занимает вся структура классов и другая обвязка объекта.
from pympler import asizeof
print(f'Pympler: {asizeof.asizeof(c)}\t\t'
f'{asizeof.asizeof(s)}\t\t'
f'{asizeof.asizeof(d)}\t\t'
f'{asizeof.asizeof(t)}'
)
CLS SLT DCT TPL
Pympler: 416 152 496 160
И вот тут класс со слотами оказывается самым оптимальным решением! И это правильно. А словарь в этом тесте оказался самый расточительный.
#tricks #libs
Наверняка вы знаете что такое перегруженная функция в С++. Если нет, то всё просто.
В С++ можно создать несколько функций с одинаковым названием но разными типами аргументов. И это будут разные функции.
Во время вызова функции будет выбрана та её версия которая подходит по типам аргументов. Такая конструкция называется параметрический полиморфизм.
Это удобно, когда мы точно не знаем какого типа прилетит аргумент и хотим обработать разные ситуации.
Как мы это поведение можем повторить в Python? Обычно через проверку типов.
Начиная с версии 3.4 в Python добавили способ делать "перегруженные" функции более элегантно. Это декоратор singledispatch.
Создадим нашу исходную функцию которая по умолчанию выбрасывает ошибку.
В качестве аргумента указывайте тип который данная функция обрабатывает
Имя новой функции не имеет значения, часто её называют просто "_"
◽️ Данный способ работает только с первым аргументом. Все остальные аргументы будут переданы как есть и не участвуют в выборе нужной функции.
◽️ В версии 3.8 доступен декоратор
#tricks #libs
В С++ можно создать несколько функций с одинаковым названием но разными типами аргументов. И это будут разные функции.
Во время вызова функции будет выбрана та её версия которая подходит по типам аргументов. Такая конструкция называется параметрический полиморфизм.
Это удобно, когда мы точно не знаем какого типа прилетит аргумент и хотим обработать разные ситуации.
Как мы это поведение можем повторить в Python? Обычно через проверку типов.
def func(value):Не очень красиво 🧐
if isinstance(value, int):
return func_int(value)
elif isinstance(value, str):
return func_str(value)
else:
raise NotImplementedError
Начиная с версии 3.4 в Python добавили способ делать "перегруженные" функции более элегантно. Это декоратор singledispatch.
Создадим нашу исходную функцию которая по умолчанию выбрасывает ошибку.
@singledispatchДекоратор добавил для объекта
def func(value)
raise NotImplementedError
func новую функцию register() с помощью которой можем регистрировать перегруженные функции.В качестве аргумента указывайте тип который данная функция обрабатывает
@func.register(int)Вместо указания типа в аргументах можно использовать аннотации аргумента функции
def func_int(x):
print("INT:", x)
@func.registerЕсли не указать тип одним из этих способов то получите ошибку TypeError.
def func_str(x: str):
print("STR:", x)
Имя новой функции не имеет значения, часто её называют просто "_"
@func.register(list)Если одна функция должна обработать несколько типов, то просто наслаиваем декоратор
def _(x):
print("LIST", x)
@func.register(float)Теперь у нас есть 5 отдельных функций которые вызываются в зависимости от типа передаваемого аргумента. При этом всё выглядит логично и компактно. Обработка каждого случая находится в своей отдельной функции!
@func.register(Decimal)
def _(x):
print(f'{type(x).__name__.upper()}:', x)
>>> func(1)------
INT: 1
>>> func('Python')
STR: Python
>>> func(1.2)
FLOAT: 1.2
>>> func({})
NotImplementedError
◽️ Данный способ работает только с первым аргументом. Все остальные аргументы будут переданы как есть и не участвуют в выборе нужной функции.
◽️ В версии 3.8 доступен декоратор
singledispatchmethod с таким же функционалом но для методов класса.#tricks #libs
В одном из прошлых постов был вопрос в комментариях по поводу закрытия файла.
Тогда я бегло пояснил что Python сам собирает мусор в памяти.
Давайте пройдемся по этому вопросу более внимательно.
Когда вы открываете файл не сохраняя его в переменную, на самом деле файл остаётся открытым. Ссылка на него теряется где-то в памяти пока сборщик мусора не доберется до него.
Давайте сделаем несколько экспериментов. Откроем файл не сохраняя его в переменную и поищем этот объект в памяти.
Для поиска будем использовать вот такую функцию
Тест второй: теперь откроем файл просто в коде, можно в интерактивной консоли.
_________________
Мои примеры порой содержат оптимизации в угоду краткости но в ущерб правильности.
#tricks
Тогда я бегло пояснил что Python сам собирает мусор в памяти.
Давайте пройдемся по этому вопросу более внимательно.
Когда вы открываете файл не сохраняя его в переменную, на самом деле файл остаётся открытым. Ссылка на него теряется где-то в памяти пока сборщик мусора не доберется до него.
Давайте сделаем несколько экспериментов. Откроем файл не сохраняя его в переменную и поищем этот объект в памяти.
Для поиска будем использовать вот такую функцию
def check_file():Тест первый: файл, открытый в функции
import io, gc
for obj in gc.get_objects():
if isinstance(obj, io.TextIOWrapper) and \
obj.name == 'testfile':
print('File', obj.name, 'is closed:', obj.closed)
return
print('Not found')
def func():Вызываем функцию и проверяем наличие файла
open('testfile', 'w')
>>> func()Здесь всё предсказуемо. Все локальные переменные функции удаляются когда функция завершится. А при удалении файл закрывается.
>>> check_file()
Not found
Тест второй: теперь откроем файл просто в коде, можно в интерактивной консоли.
open('testfile', 'w')
И снова он не сохранён в переменную, а значит будет удалён сборщиком мусора. Проверим:>>> check_file()Бывалые сразу же скажут, что файл улетел в переменную "_", и будут правы!
File testfile is closed: False
>>> print(_)Давайте обнулим её, можно просто распечатать любое число в консоли
<_io.TextIOWrapper name='testfile' mode='w' encoding='UTF-8'>
>>> 123Проверим
>>> print(_)
123
>>> check_file()➡️ Отсюда вывод: Всегда явно закрывайте файлы! Не рассчитывайте что кто-то (gc) сделает это за вас.
Not found
_________________
Мои примеры порой содержат оптимизации в угоду краткости но в ущерб правильности.
#tricks
В Python есть удобный режим, определяющий код с неверно закрытыми ресурсами. Этот режим называется Development Mode и включается двумя способами:
Переменная окружения
Вот пример файла
При этом ResourceWarning всё равно будет выброшен, причём еще до использования psutil.
➡️ Отсюда вывод: Всегда явно закрывайте файлы! Пишите чистый и предсказуемый код.
#tricks #libs
Переменная окружения
export PYTHONDEVMODE=1Аргументы
python3 app.py
python3 -X dev app.pyЕсли не закрыть файл должным образом, то вы получите в консоль ResourceWarning.
Вот пример файла
# app.pyВ этом примере я использую пакет psutil, чтобы убедиться, что перед выходом открытых файлов в моём процессе не осталось.
import psutil, os
open('testfile', 'w')
123
print('process handlers:', psutil.Process(os.getpid()).open_files())
При этом ResourceWarning всё равно будет выброшен, причём еще до использования psutil.
app.py:3: ResourceWarning: unclosed file <_io.TextIOWrapper name='testfile' mode='w' encoding='UTF-8'>Для отображения строки с ошибкой требуется включить tracemalloc, тоже с помощью переменой или аргументов запуска. Смотрите примеры в доке.
open('testfile', 'w')
Object allocated at (most recent call last):
File "app.py", lineno 3
open('testfile', 'w')
process handlers: []
➡️ Отсюда вывод: Всегда явно закрывайте файлы! Пишите чистый и предсказуемый код.
#tricks #libs
👍1
Особенно внимательно за закрытием файлов нужно следить в задачах где вы обрабатываете много файлов.
Операционная система имеет ограничение на количество открытых файлов процессом и вы быстро можете дойти до этого предела.
Изменить лимит можно командой
#tricks
Операционная система имеет ограничение на количество открытых файлов процессом и вы быстро можете дойти до этого предела.
import osЧтобы узнать лимит на Linux вызовите команду
lst = []
for i in range(100000):
lst.append(open(os.devnull, 'w'))
OSError: [Errno 24] Too many open files: 'nul'
ulimit -n(Полный список лимитов
ulimit -a)Изменить лимит можно командой
ulimit -n 2048На Windows можно это сделать с помощью кода
>>> import ctypes➡️ Отсюда вывод: Всегда явно закрывайте файлы! Иначе можете упереться в ограничения системы.
>>> ctypes.windll.msvcrt._getmaxstdio()
512
>>> ctypes.windll.msvcrt._setmaxstdio(2048)
2048
#tricks
Python 3.10 Release Stream — with Pablo Galindo
Стрим, посвящённый релизу Python 3.10!
➡️ https://www.youtube.com/watch?v=AHT2l3hcIJg
Стрим, посвящённый релизу Python 3.10!
➡️ https://www.youtube.com/watch?v=AHT2l3hcIJg
Релиз Python 3.10 случился! Все быстро побежали использовать новые type hints, pattern matching и всё такое😁
А между тем, на днях вышел Qt6.2.
Наконец-то портировали такие модули как QtBluetooth, QtMultimedia, QtWebEngine, QtWebView и другие полезняхи.
Если вы этого ждали, то пора действовать!
PySide6 тоже подтянулся по версии.
#qt #libs
А между тем, на днях вышел Qt6.2.
Наконец-то портировали такие модули как QtBluetooth, QtMultimedia, QtWebEngine, QtWebView и другие полезняхи.
Если вы этого ждали, то пора действовать!
PySide6 тоже подтянулся по версии.
#qt #libs
Все уже успели обсудить новые фишки в Python 3.10, такие как ускорение работы базовых типов, удобная типизация и особенно новый паттерн матчинг.
Только ленивый не рассказывал про паттерн матчинг!
Давайте я прикинусь ленивым (но это не так😉) и не буду повторяться. Расскажу про другое нововведение.
В противовес мега полезному pattern matching эта штука, на первый взгляд, имеет сомнительную полезность🧐
В Python 3.10 у типа int появился новый метод int.bit_count().
Что он делает? Возвращает количество единиц в битовом представлении числа.
Что? Зачем? Почему? 😭❓😱
Это не bit_length(), возвращающий количество бит, необходимых для записи данного числа.
И это не
Зачем нам количество ненулевых бит в битовом представлении? Особенно когда новый метод это просто эквивалент строки:
An efficient popcount would be useful for numerics, parsing binary formats, scientific applications and others.
Эта функция называется Population Count (подсчёт популяции). Применяется в алгоритмах теории информации. Почитайте про Теорию Хэминга чтобы понять чуть больше чем сейчас.
Если коротко, это такие алгоритмы, помогающие быстро определить схожесть или различие строк основываясь на их битовом представлении.
Этим применение не ограничивается. Подсчет единиц может быть полезен при работе с битовыми картами.
В Redis тоже есть подобная команда.
Как считаете, это маленькая удобная функция делающая Python ближе к научному сообществу или бесполезная трата места в документации?
#libs
Только ленивый не рассказывал про паттерн матчинг!
Давайте я прикинусь ленивым (но это не так😉) и не буду повторяться. Расскажу про другое нововведение.
В противовес мега полезному pattern matching эта штука, на первый взгляд, имеет сомнительную полезность🧐
В Python 3.10 у типа int появился новый метод int.bit_count().
Что он делает? Возвращает количество единиц в битовом представлении числа.
Что? Зачем? Почему? 😭❓😱
Это не bit_length(), возвращающий количество бит, необходимых для записи данного числа.
И это не
struct.calcsize("I"), возвращающий количество байт, в которые точно поместится любой int.Зачем нам количество ненулевых бит в битовом представлении? Особенно когда новый метод это просто эквивалент строки:
bin(num).count("1")
Цитата из слов автора.An efficient popcount would be useful for numerics, parsing binary formats, scientific applications and others.
Эта функция называется Population Count (подсчёт популяции). Применяется в алгоритмах теории информации. Почитайте про Теорию Хэминга чтобы понять чуть больше чем сейчас.
Если коротко, это такие алгоритмы, помогающие быстро определить схожесть или различие строк основываясь на их битовом представлении.
Этим применение не ограничивается. Подсчет единиц может быть полезен при работе с битовыми картами.
В Redis тоже есть подобная команда.
Как считаете, это маленькая удобная функция делающая Python ближе к научному сообществу или бесполезная трата места в документации?
#libs
👍1
Размышления насчет ускорений Python идут полным ходом. Прежде всего идут рассуждения о выпиливании GIL, не без участия Гвидо.
Но никто не отменял ускорение выполнения задач через распараллеливание различными способами. Лично я часто использую threading и multiprocessing для массовой обработки картинок или многопоточной закачки файлов. Для фоновой очереди задач использую Celery а для высоконагруженного распределённого рендеринга у меня в арсенале RenderManager'ы Afanasy и Deadline.
И тут я подумал, я так давно на этом стеке, что, вероятно, упускаю какие-то новые решения. И решил поискать что там у нас из свежего...
Вы наверняка знаете что Github полон самыми разными Awesome-листами. Есть даже топик Awesome Lists с подборкой этих списков.
Решил я там поискать какой-то список решений для параллельных/распределённых вычислений на Python. Нашел несколько ссылок в основном Awesome-списке по Python. Не густо 😢, список для С++ и того побольше будет.
В общем, покопавшись немного в сети, нашел-таки подобный список и для Python - Parallel Processing and Multiprocessing in Python. Интересная подборка модулей, есть на что залипнуть!
Вот бы кто запилил нормально на Github в awesome-parallel-computing, как это сделано в Awesome Asyncio.
#libs
Но никто не отменял ускорение выполнения задач через распараллеливание различными способами. Лично я часто использую threading и multiprocessing для массовой обработки картинок или многопоточной закачки файлов. Для фоновой очереди задач использую Celery а для высоконагруженного распределённого рендеринга у меня в арсенале RenderManager'ы Afanasy и Deadline.
И тут я подумал, я так давно на этом стеке, что, вероятно, упускаю какие-то новые решения. И решил поискать что там у нас из свежего...
Вы наверняка знаете что Github полон самыми разными Awesome-листами. Есть даже топик Awesome Lists с подборкой этих списков.
Решил я там поискать какой-то список решений для параллельных/распределённых вычислений на Python. Нашел несколько ссылок в основном Awesome-списке по Python. Не густо 😢, список для С++ и того побольше будет.
В общем, покопавшись немного в сети, нашел-таки подобный список и для Python - Parallel Processing and Multiprocessing in Python. Интересная подборка модулей, есть на что залипнуть!
Вот бы кто запилил нормально на Github в awesome-parallel-computing, как это сделано в Awesome Asyncio.
#libs
GitHub
GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over 420 million projects.
👍1
Модуль pythonnet позволяет интегрировать ваш код на Python с .NET приложениями.
Например, запускать Python модули внутри .NET или импортировать DLL библиотеки в Python.
📖 Вики по модулю
📕 Урок на гитхабе
📙 Пара примеров использования
📌 Пример от меня:
Использование библиотеки от всем известного софта мониторинга Open Hardware Monitor.
Когда его скачаете, обнаружите там библиотеку OpenHardwareMonitorLib.dll. Вот она нам и нужна!
Для начала поставьте модуль pythonnet
Теперь нам доступен модуль clr (Common Language Runtime) с помощью которого можно делать DLL доступными для импорта
Вот и всё, можно импортировать и использовать
__________________
PS. Некоторые устройства для получения полной информации требуют запуска от имени администратора.
Например, если видите в списке устройств некий Generic Hard Disk или запрос значения сенсора вернуло None, то это как раз тот случай.
#libs
Например, запускать Python модули внутри .NET или импортировать DLL библиотеки в Python.
📖 Вики по модулю
📕 Урок на гитхабе
📙 Пара примеров использования
📌 Пример от меня:
Использование библиотеки от всем известного софта мониторинга Open Hardware Monitor.
Когда его скачаете, обнаружите там библиотеку OpenHardwareMonitorLib.dll. Вот она нам и нужна!
Для начала поставьте модуль pythonnet
pip install pythonnetЕсли установка завершилась ошибкой, скорее всего ваша версия Python еще не поддерживается. Поищите WHL здесь. А потом устанавливайте так:
pip install ...\2.5.2-cp39-cp39-win_amd64.whlЛибо попробуйте другую версию Python.
Теперь нам доступен модуль clr (Common Language Runtime) с помощью которого можно делать DLL доступными для импорта
import clrПредполагается, что библиотека лежит в текущей рабочей директории
from pathlib import Path
clr.AddReference(str(
Path('OpenHardwareMonitorLib.dll').absolute()
))
Вот и всё, можно импортировать и использовать
from OpenHardwareMonitor.Hardware import ComputerТеперь можете делать свою мониторилку ресурсов. Например вот так можно считывать данные сенсоров
c = Computer()
c.CPUEnabled = True
c.GPUEnabled = True
c.RAMEnabled = True
c.HDDEnabled = True
c.Open()
for hw in c.Hardware:
print(hw.Name)
c.Close()
...Здесь
for hw in c.Hardware:
hw.Update()
for sensor in hw.Sensors:
print(sensor.Identifier, sensor.get_Value())
...
hw.Update() нужен для обновления данных сенсоров на текущий момент, на случай если у вас бесконечный цикл опроса сенсоров.__________________
PS. Некоторые устройства для получения полной информации требуют запуска от имени администратора.
Например, если видите в списке устройств некий Generic Hard Disk или запрос значения сенсора вернуло None, то это как раз тот случай.
#libs
PyPI
pythonnet
.NET and Mono integration for Python
👍1
В модуле logging предусмотрен немного необычный способ форматирования строки без форматирования.
Если вам требуется указать в строке сообщения какой-либо аргумент то обычно это делается форматированием строки
Функция записи сообщения должна быть очень быстрой. Да, она в любом случае занимает время, но чем меньше тем лучше. И особенно, когда это сообщение не проходит по фильтру уровня логирования.
Например, у меня установлен уровень WARNING и выполняется вот такой вызов
Сообщение не попадает под установленный уровень логирования и будет проигнорировано. Это обрабатывается сразу же первой командой в вызываемой функции debug. Но при этом форматирование строки всё равно произойдёт!
И проблема не в самом форматировании, которое достаточно быстрое (даже при складывании строк через "+"), а в тех возможных действиях, которые придется вызвать для преобразования объекта user в строку.
Возможно, там будет запрос в БД, разбор больших массивов данных или еще что-то не очень быстрое (или не очень умное🤪).
Нам всё это придётся посчитать чтобы потом.....ничего с этим не сделать.
Поэтому правильно писать так:
#libs #tricks
logging.info('Message %s %s', arg1, arg2)
На самом деле, если вы его не используете то вы делаете неправильно!⚠️Если вам требуется указать в строке сообщения какой-либо аргумент то обычно это делается форматированием строки
logging.info('New value is %s' % value)
Или любой другой доступный нам способlogging.info(f'New value is {value}')
logging.info(f'{value=}')
Кажется, всё логично, все так делают. Но нет, это ошибка! 😫Функция записи сообщения должна быть очень быстрой. Да, она в любом случае занимает время, но чем меньше тем лучше. И особенно, когда это сообщение не проходит по фильтру уровня логирования.
Например, у меня установлен уровень WARNING и выполняется вот такой вызов
logging.debug(f'Current user: {user}')
Что произойдет? Сообщение не попадает под установленный уровень логирования и будет проигнорировано. Это обрабатывается сразу же первой командой в вызываемой функции debug. Но при этом форматирование строки всё равно произойдёт!
И проблема не в самом форматировании, которое достаточно быстрое (даже при складывании строк через "+"), а в тех возможных действиях, которые придется вызвать для преобразования объекта user в строку.
Возможно, там будет запрос в БД, разбор больших массивов данных или еще что-то не очень быстрое (или не очень умное🤪).
Нам всё это придётся посчитать чтобы потом.....ничего с этим не сделать.
Поэтому правильно писать так:
logging.debug('Current user: %s', user)
Мы просто передаём подготовленную неформатированную строку и аргументы для форматирования, это не требует вычислений. Но само форматирование и сопутствующие вызовы произойдут только в случае когда это действительно потребуется, то есть уровень сообщения попадает под условия настройки текущего логгера.#libs #tricks
Если часто работаете с архивами, то наверняка знакомы с модулем zipfile.
Нет ничего сложного добавить директорию в архив.
Здесь проще, даже с
▫️ В данном случае функция из
Поддерживаются форматы
▫️ Из недостатков можно назвать невозможность запаковать просто один файл. Источником может быть только директория. Проблема легко решается, но всё же.
▫️ Интересный момент. При наличии в Python2 функции
#libs #tricks
Нет ничего сложного добавить директорию в архив.
import zipfileДовольно немногословно. Но можно короче! В модуле
from pathlib import Path
dir_name = '~/input_files'
zip_name = '~/archive.zip'
with zipfile.ZipFile(zip_name, 'w') as zip:
for file in Path(dir_name).glob('**/*'):
zip.write(file, file.relative_to(dir_name).as_posix())
shutil уже есть готовый методdir_name = '~/input_files'А что насчет распаковки?
zip_name = '~/archive'
zip_file = shutil.make_archive(zip_name, 'zip', root_dir=dir_name)
Здесь проще, даже с
zipfile это одна строкаzip_file = '~/archive.zip'Ну и тем более в
out_dir = '~/out_dir'
zipfile.ZipFile(zip_file).extractall(out_dir)
shutil
shutil.unpack_archive(zip_file, out_dir)В примерах не делается expanduser для краткости
▫️ В данном случае функция из
shutil более универсальна, так как второй аргумент format задаёт алгоритм сжатия, от чего зависит выбор библиотеки. Если написать формат tar, то вместо zipfile будет использоваться tarfile.Поддерживаются форматы
zip, tar, gztar, bztar, xztar. Но только если на текущем хосте доступны соответствующие библиотеки.▫️ Из недостатков можно назвать невозможность запаковать просто один файл. Источником может быть только директория. Проблема легко решается, но всё же.
▫️ Интересный момент. При наличии в Python2 функции
shutil.make_archive() там отсутствует shutil.unpack_archive(). А появился он только в 3.7! Не очень понятно почему, но это еще один повод переходить на Python3 😊#libs #tricks
🤟😜🍺🎁🎉🍻🎂
Поздравляю всех 3Dшников с проф-праздником!
PS. А еще на канале юбилейный пост под номером 300! 😎
#offtop
Поздравляю всех 3Dшников с проф-праздником!
PS. А еще на канале юбилейный пост под номером 300! 😎
#offtop
😋 Заметка от читателя @nencoru
Как смержить несколько файлов с отсортированными строками в один файл, тоже отсортированный?
🔸 Исходный файл:
▫️ в одной строке находится одна запись
▫️ запись содержит предсказуемое поле с некими данными для сортировки. Например, логи с указанием времени.
▫️ все записи в файле отсортированы по этому полю
🔸 Задача:
Смержить несколько таких файлов так, чтобы в финальном файле все записи были также отсортированы.
🔸 Решение 1:
Предположим, у меня JSON-логи
Это означает, что вам потребуется оперативной памяти 5*len(files) Gb.
И уже не каждый компьютер сможет смержить 3-4 таких файла. А если их 100?
fileinput может помочь написать более красивый код, но с памятью не поможет.
🔸 Решение 2:
Можно использовать готовую функцию heapq.merge() из стандартного модуля heapq!
Heap - это бинарное дерево, где каждый родительский элемент в дереве имеет значение меньшее чем дочерний.
То есть, по умолчанию все элементы как-либо отсортированы.
И тут вы спросите: что за магия?
Тоже самое только без расхода памяти? Волшебный генератор всех спасёт?
Нет, за всё приходится платить. В случае с heapq весь процесс драматически замедлится.
Но задача будет выполнена! 😎
Сделал для вас синтетический пример для генерации и мержа подобных файлов
Код смотреть здесь ↗️
▫️ make_logs() генерит 30 файлов по 50Mb для теста
▫️ merge_list() мержит файлы через простой список
▫️ merge_heapq() мержит файлы через heapq
▫️ memory_profiler считает используемую память (нужно установить модуль)
▫️ также есть замер времени
Кому лениво там же смотрите мои тесты:
1.5Gb и 19.5с против 19Mb и 2м 43с
памяти в 80 раз меньше, но времени в 8 раз больше
⚠️ ВАЖНО
для чистоты эксперимента запускать следует из консоли и по одному тесту на процесс. То есть закоментили второй, запустили первый, закоментили первый, запустили второй.
#bacik
Как смержить несколько файлов с отсортированными строками в один файл, тоже отсортированный?
🔸 Исходный файл:
▫️ в одной строке находится одна запись
▫️ запись содержит предсказуемое поле с некими данными для сортировки. Например, логи с указанием времени.
▫️ все записи в файле отсортированы по этому полю
🔸 Задача:
Смержить несколько таких файлов так, чтобы в финальном файле все записи были также отсортированы.
🔸 Решение 1:
Предположим, у меня JSON-логи
files = ['file1.jsonl', 'file2.jsonl', ...]
data = []
for file in files:
with open(file) as f:
data.expand(
f.readlines()
)
data.sort(key=lambda line: json.loads(line)['timestamp'])
with open('merged.jsonl', 'w') as f:
f.writelines(data)
Усложним задачу — размер каждого файла 5Gb 😱Это означает, что вам потребуется оперативной памяти 5*len(files) Gb.
И уже не каждый компьютер сможет смержить 3-4 таких файла. А если их 100?
fileinput может помочь написать более красивый код, но с памятью не поможет.
🔸 Решение 2:
Можно использовать готовую функцию heapq.merge() из стандартного модуля heapq!
Heap - это бинарное дерево, где каждый родительский элемент в дереве имеет значение меньшее чем дочерний.
То есть, по умолчанию все элементы как-либо отсортированы.
from heapq import merge
items = [
[3,2,6],
[1,5,4]
]
print(list(merge(*items)))
# [1, 2, 3, 4, 5, 6]
А учитывая, что merge это генератор, умеет работать с файлами и ему можно передать функцию для сортировки, он отлично подойдет для нашей задачи, так как полной загрузки в память не происходит!И тут вы спросите: что за магия?
Тоже самое только без расхода памяти? Волшебный генератор всех спасёт?
Нет, за всё приходится платить. В случае с heapq весь процесс драматически замедлится.
Но задача будет выполнена! 😎
Сделал для вас синтетический пример для генерации и мержа подобных файлов
Код смотреть здесь ↗️
▫️ make_logs() генерит 30 файлов по 50Mb для теста
▫️ merge_list() мержит файлы через простой список
▫️ merge_heapq() мержит файлы через heapq
▫️ memory_profiler считает используемую память (нужно установить модуль)
▫️ также есть замер времени
Кому лениво там же смотрите мои тесты:
1.5Gb и 19.5с против 19Mb и 2м 43с
памяти в 80 раз меньше, но времени в 8 раз больше
⚠️ ВАЖНО
для чистоты эксперимента запускать следует из консоли и по одному тесту на процесс. То есть закоментили второй, запустили первый, закоментили первый, запустили второй.
#bacik
Gist
Merging of huge sorted files
Merging of huge sorted files. GitHub Gist: instantly share code, notes, and snippets.
👍3