$ python -m usefulВыполнит код
__main__.py сразу после инициализации __init__.py из пакета usefulПри импорте модулей или пакетов вызывается функция
__import__:module = __import__("module", globals(), None, None, 0)Поиск
__import__ в builtins происходит динамически, поэтому можно ее удалить/изменить:def import_wrapper(name, *args, imp=__import__): print("importing ", name) return imp(name, *args)builtins.__import__ = import_wrapperПримерный аналог того, что делает import (читаем файл, компилируем в байткод и выполняем байткод):
import typesmod = types.ModuleType("useful")with open("./useful.py") as handle: source = handle.read()code = compile(source, "useful.py", mode="exec")exec(code, mod.__dict__)useful = modЗагрузка модуля с проверкой есть ли он в системе:
from importlib.util import find_specif find_spec("_useful_speedups"): import _useful_speedups as usefulelse: import usefulОбъявление свойства класса
class TestProperty1: def _get_attr(self): return self._x def _set_attr(self, x): assert x >= 0, "non-negative value required" self._x = x def _del_attr(self): del self._x x = property(_get_attr, _set_attr, _del_attr)Объявление свойства через декоратор
class TestProperty2: @property def x(self): return self._x @x.setter def x(self, new_x): assert x >= 0, "non-negative value required" self._x = new_x @x.deleter def x(self): del self._xДескриптор - экземпляр класса, реализующий протокол дескрипторов (методы
Экземпляр дескриптора один для всего экземпляра класса поэтому в нем нельзя по self.val хранить значение свойства.
Используя метки можно хранить данные в экземпляре класса, пример:
__get__, __set__, __delete__), свойство которое можно переиспользовать.Экземпляр дескриптора один для всего экземпляра класса поэтому в нем нельзя по self.val хранить значение свойства.
Используя метки можно хранить данные в экземпляре класса, пример:
class NonNegative: def __init__(self, label): # метка по которой сохраняем в instance # данные дескриптора self.label = "__" + label def __get__(self, instance, owner): return instance.__dict__[self.label] def __set__(self, instance, value): assert value >= 0, "non-negative value required" instance.__dict__[self.label] = value def __delete__(self, instance): del instance.__dict__[self.label]class TestProperty3: x = NonNegative("x") y = NonNegative("y")data descriptor - дескриптор у которого реализован метод __set__, тогда при запросе данных всегда будет вызываться __get__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 42a = A()
a.f
При вызове первый раз на чтение атрибута
f non-data дескриптор f() реализованный через декоратор @cached_property вызовется один раз и перезапишет вычисленное значение в атрибут экземпляра класса A - fСтатические методы класса
class SomeClass: @staticmethod def do_something(): passSomeClass.do_something()Метод класса возвращающий экземпляр класса для организации хитрых инициализаций
class Settings: @classmethod def read_from(cls, path): res = cls() # do smth with path return resSettings.read_from("settings.ini")@classmethod гарантирует, что read_from будет вызван не с экземпляром класса, а с классом@staticmethod гарантирует, что первым параметром не будет self, пользы не много, зато можно подчеркнуть, что данный метод статичен по отношению к экземпляру класса