Фишки Python
29 subscribers
2 photos
3 files
29 links
Всё что ты хотел узнать, но ленился спросить.

Декораторы, итераторы и контракты.
Download Telegram
non-data descriptor - дескриптор у которого нет метода __set__, тогда при запросе данных проверяется наличие атрибута у дескриптора и если его нет, то попадаем в __get__
cached property - декоратор, который реализуется поверх non-data descriptor и вычисляется один раз перезаписывая атрибут в котором хранится дескриптор заменяя его вычисленным значением
class cached_property:
def __init__(self, method):
self._method = method
def __get__(self, instance, owner):
if instance is None:
return self
value = self._method(instance)
setattr(instance, self._method.__name__, value)
return value

Пример использования:

class A:
@cached_property
def f(self):
return 42

a = A()
a.f

При вызове первый раз на чтение атрибута f non-data дескриптор f() реализованный через декоратор @cached_property вызовется один раз и перезапишет вычисленное значение в атрибут экземпляра класса A - f
@property - декоратор реализующий протокол дескрипторов
Статические методы класса

class SomeClass:
@staticmethod
def do_something():
pass

SomeClass.do_something()
Метод класса возвращающий экземпляр класса для организации хитрых инициализаций

class Settings:
@classmethod
def read_from(cls, path):
res = cls()
# do smth with path
return res

Settings.read_from("settings.ini")
@classmethod гарантирует, что read_from будет вызван не с экземпляром класса, а с классом
@staticmethod гарантирует, что первым параметром не будет self, пользы не много, зато можно подчеркнуть, что данный метод статичен по отношению к экземпляру класса
Метаклассы!
__new__ - создает экземпляр класса, т.е. это конструктор возвращяющий экземпляр, например так:
return super().__new__(cls)
__new__ - статичный метод класса
__init__ - инициализирует созданный экземпляр
class ImpossibleIsNothing(metaclass=lambda *args, **kwargs: 42): pass

Превращает класс в число.
С помощью метаклассов можно сделать любое изменение класса и результат metaclass-а запишется в имя класса.
Метаклассы могут изменять тип словаря в котором хранятся атрибуты класса через метод __prepare__
В отличие от декораторов метаклассы наследуются потомками, т.е. не нужно каждый раз декорировать потомков для реализации задуманного поведения
Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).

— Тим Питерс
Метаклассы полезны для объектно-ориентированных интерфейсов к БД
В стандартной библиотеке есть модуль abc, который с помощью metaclass-ов позволяет писать абстрактные классы в python
import abc

class Iterable(metaclass=abc.ABCMeta):
@abc.abstractmethod
def __iter__(self):
pass

class Something(Iterable):
pass

>>> Something()
TypeError: Can't instantiate abstract class Something with abstract methods __iter__