Python Заметки
Интересные заметки и обучающие материалы по Python Контакт: @paulwinex ⚠️ Рекламу на канале не делаю!⚠️ Хештеги для поиска: #tricks #libs #pep #basic #regex #qt #django #2to3 #source #offtop
Mostrar más- Suscriptores
- Cobertura postal
- ER - ratio de compromiso
Carga de datos en curso...
Carga de datos en curso...
self
.
Если же он не нужен то просто пробрасываем его через *args
def decorator_func(func):
def wrapped(*args, **kwargs):
print('decorator_func')
return func(*args, **kwargs)
return wrapped
class MyClass:
@decorator_func
def method(self):
print('call method')
MyClass().method()
# decorator_func
# call method
▫️Способ 2. Методы класса.
Иногда бывает удобно если декоратор жестко привязан к классу и используется только в нём.
В таком случае можно сделать staticmethod
. Это будет выглядеть страшно, но работать будет (тестировано на 3.11)
Очевидно, что декоратор должен быть объявлен раньше метода.
class MyClass:
@staticmethod
def decorator(func):
def wrapper(*args, **kwargs):
print('decorator from staticmethod')
return func(*args, **kwargs)
return wrapper
@decorator.__func__
def method(self):
print('method called')
MyClass().method()
# decorator from staticmethod
# method called
Тоже самое будет и с classmethod
, но еще хуже.
class MyClass:
@classmethod
def decorator(func):
def wrapper(self, *args, **kwargs):
print('decorator from classmethod')
return func(self, *args, **kwargs)
return wrapper
@decorator.__func__
def method(self):
print('method called')
MyClass().method()
# decorator from classmethod
# method called
Где-то потерялся аргумент cls
. Скорее всего это можно решить но лучше не надо. Оба варианта выглядят страшненько 🫣
▫️Способ 3. Вложенный класс и staticmethod
class MyClass:
class deco:
@staticmethod
def my_decorator(func):
def wrapper(*args, **kwargs):
print('decorator from subclass')
return func(*args, **kwargs)
return wrapper
@deco.my_decorator
def method(self):
print('method called')
MyClass().method()
# decorator from subclass
# method called
Получаем чтото вроде микса способов 1 и 2: функция вложена в отдельный класс.
Лучшей практикой является способ 1 - обычные функции.
Всего пару раз за практику я использовал 3й способ, когда декоратор был намертво привязан к классу и нигде больше не мог использоваться (например, отправлял вызов метода на воркера в другой процесс, не спрашивайте почему так, просто так было нужно 🤪)
Способ 2 не советую. Это, скорей, разминка для ума чем практический пример.
ЗЫ. wraps
пропустил для краткости
#tricksset()
.
При добавлении элемента в set
происходит сравнение этого объекта по хешу. Если хеш совпадает то объект не добавляется.
class A:
def __init__(self, pk: int):
self.pk = pk
def __repr__(self):
return f"{self.__class__.__name__}(pk={self.pk})"
set([A(pk=1), A(pk=2), A(pk=2)])
>>> {A(pk=1), A(pk=2), A(pk=2)}
Далее для краткости метод `__repr__()` я буду пропускать
По умолчанию в расчёте хеша, помимо прочего, используется адрес в памяти, который можно получить с помощью функции id()
, поэтому все объекты считаются разными. Чтобы изменить способ сравнения объектов нам требуется переопределить метод __eq__()
class A:
def __init__(self, pk: int):
self.pk = pk
def __eq__(self, other):
return self.pk == other.pk
set([A(pk=1), A(pk=2), A(pk=2)])
>>> TypeError: unhashable type: 'A'
Теперь в дело вступает логика, описаная в документации.
Если вы переопределили __eq__()
то следует переопределить и __hash__()
.
class A:
def __init__(self, pk: int):
self.pk = pk
def __eq__(self, other):
return self.pk == other.pk
def __hash__(self):
return hash(self.pk)
set([A(pk=1), A(pk=2), A(pk=2)])
>>> {A(pk=1), A(pk=2)}
Отлично, теперь всё работает.
Этот же принцип действует и при наследовании. Допустим вы создали дочерний класс
class B(A):
pass
set([B(pk=1), B(pk=2), B(pk=2)])
>>> {B(pk=1), B(pk=2)}
Теперь следует учитывать вот такое поведение
hash(A(1)) == hash(B(1))
>>> True
set([A(1), B(1)])
>>> {A(pk=1)}
Инстансы А и В считаются идентичными. Можно учесть это в __eq__()
.
class A:
...
def __eq__(self, other):
return isinstance(other, self.__class__) and self.pk == other.pk
...
Или в __hash__()
class A:
...
def __hash__(self):
return hash((self.pk, self.__class__))
...
Но если вдруг решите как-то изменить способ сравнения в классе В...
class B(A):
def __eq__(self, other):
return abs(self.pk) == abs(other.pk)
set([B(pk=1), B(pk=2), B(pk=2)])
>>> TypeError: unhashable type: 'B'
Снова получите ошибку. Та же логика - при переопределении метода __eq__()
в новом классе метод __hash__()
автоматически становится None
и его тоже требуется переопределить.
# tricksObjects, values and types: Objects are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects. (In a sense, and in conformance to Von ...
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
#tricksSource code: Lib/subprocess.py The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace seve...
Task scheduling library for Python. Contribute to agronholm/apscheduler development by creating an account on GitHub.
import psutil
def list_file_handlers(process_name):
for proc in psutil.process_iter():
if proc.name().lower().startswith(process_name):
for file in proc.open_files():
print(file)
list_file_handlers('python')
Функция вернёт имя процесса который занял файл. Если файл не занят то вернёт None
.
def who_is_use(fpath):
for proc in psutil.process_iter():
for item in proc.open_files():
if fpath == item.path:
return proc.name()
Для использования требуются админские права.
#libsCross-platform lib for process and system monitoring in Python - giampaolo/psutil
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()
На самом деле я использую такую конструкцию только в прототипах тестов или вспомогательных функциях тестов. В продакшн такое обычно не попадает.
#tricksTu plan actual sólo permite el análisis de 5 canales. Para obtener más, elige otro plan.