cookie

Utilizamos cookies para mejorar tu experiencia de navegación. Al hacer clic en "Aceptar todo", aceptas el uso de cookies.

avatar

Python Заметки

Интересные заметки и обучающие материалы по Python Контакт: @paulwinex ⚠️ Рекламу на канале не делаю!⚠️ Хештеги для поиска: #tricks #libs #pep #basic #regex #qt #django #2to3 #source #offtop

Mostrar más
Publicaciones publicitarias
2 567
Suscriptores
+124 horas
-27 días
-2030 días

Carga de datos en curso...

Tasa de crecimiento de suscriptores

Carga de datos en curso...

Три способа создать декоратор для метода класса. ▫️Способ 1. Обычная функция. Единственное отличие от простого декоратора функции в том, что нужно учитывать аргумент 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 пропустил для краткости #tricks
Mostrar todo...
👍 5
Нередко требуется удалять дубликаты инстансов класса. Для этого обычно используется либо циклы со сравнением некоторых атрибутов, либо тип данных set(). При добавлении элемента в 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 и его тоже требуется переопределить. # tricks
Mostrar todo...
3. Data model

Objects, 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 ...

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

Source 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...

👍 12😁 3🔥 1
⭐️ Очередной проект завершился и я снова открыт к предложениям по работе! Python Developer: CGI пайплайн, Python-инструменты, Web приложения, обучение и консультации... Полное резюме здесь https://paulwinex.com/resume/ Условия ▫️ фултайм или парттайм ▫️ удалёнка Обращаться сразу ➡️ в личку @offtop
Mostrar todo...
👍 4
Библиотека APScheduler для управления заданиями в Python. Может запускать планировщик и задания как отдельный поток (синхронный код) и как коркутины (асинхронный код), отложенные или через интервал. Что есть в APScheduler: ▫️гибкий функционал создания задачи ▫️удобное управление созданными заданиями (pause\resume, listing, modify, reschedule) ▫️кастомизация классов библиотеки ▫️различные хранилища заданий (Memory и различные БД) ▫️интеграции в фреймворки ▫️7 вариантов планировщика Три варианта тригеров для задач: ▫️по дате с помощью datetime ▫️через интервал с помощью datetime ▫️через интервал с помощью cron и другие полезности В данный момент готовится к релизу 4я версия PS. Всегда использую вместе с FastAPI, очень рекомендую к ознакомлению. #libs
Mostrar todo...
GitHub - agronholm/apscheduler at 3.x

Task scheduling library for Python. Contribute to agronholm/apscheduler development by creating an account on GitHub.

🔥 4👍 2
Photo unavailableShow in Telegram
⭐️ Поздравляю!!! ⭐️ 🌺🌼🌹🧚‍♀️👠🍀🎉 + бонус в коментах 😊
Mostrar todo...
7🤔 2👍 1
Библиотека psutil предоставляет весьма широкий инструментарий для взаимодействия с процессами. Одна из полезных функций - узнать какие файлы открыты в контексте процесса или узнать какой процесс занимает файл. Узнаём какие файлы использует процесс
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()
Для использования требуются админские права. #libs
Mostrar todo...
GitHub - giampaolo/psutil: Cross-platform lib for process and system monitoring in Python

Cross-platform lib for process and system monitoring in Python - giampaolo/psutil

6👍 4
Когда пишешь асинхронный код нужно учитывать особенности такого подхода. Всегда требуется держать в уме, когда возвращается корутина а когда реальный результат. Между этими двумя сущностями должен быть вызов через await. Вот пример синхронного запроса в базу данных с помощь sqlalchemy. Query пишу инлайном для компактности.
entities = session.execute(select(EntityModel)).scalars().all()
Всё ясно и линейно. А вот он же асинхронный.
result = await session.execute(select(EntityModel))
entities = result.scalars().all()
Это значит что session.execute возвращает корутину, или awaitable объект. Сначала его нужно выполнить через await, тогда получишь объект с которым можно дальше работать. Не хочу сказать что это мастхэв практика, но простые асинхронные запросы тоже можно сократить до одной строки. Просто использовать скобки.
entities = ( await session.execute(select(EntityModel)) ).scalars().all()
На самом деле я использую такую конструкцию только в прототипах тестов или вспомогательных функциях тестов. В продакшн такое обычно не попадает. #tricks
Mostrar todo...
👍 9
Photo unavailableShow in Telegram
Новый пакеджинг для Python uv написанный на Rust от автора быстрого линтера Ruff Что нам обещают ▫️ Эпичная скорость ▫️ Легкий переход с pip и pip-tools ▫️ Отсутствие зависимостей и дистрибуция в виде одного автономного bin файла Следим, надеемся, тестируем... #libs
Mostrar todo...
🔥 8
00:12
Video unavailableShow in Telegram
rich Библиотека для нескучного принта! Добавляет в ваш терминал цвет и разные способы форматирования текста. https://github.com/willmcgugan/rich ➡️ Мой небольшой пример #libs
Mostrar todo...
rich.mp41.44 KB
👍 10
Elige un Plan Diferente

Tu plan actual sólo permite el análisis de 5 canales. Para obtener más, elige otro plan.