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

Декораторы, итераторы и контракты.
Download Telegram
import packet.module
При импорте модуля из пакета, пакет появляется в области видимости на равне с модулем
from packet import module
Не засоряет область видимости именем пакета
__parent__ - родитель текущего модуля
from ..foo import something
импортирует из модуля foo родительского пакета текущего пакета функцию/атрибут something
Паттерн фасад для организации работы с пакетом пакетов без необходимости вникать во внутреннюю структуру пакета:

# useful/bar/__init__.py
from .boo import *
__all__ = boo.__all__

# useful/__init__.py
from .foo import *
from .bar import *
__all__ = foo.__all__ + bar.__all__
$ 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 types
mod = 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
Python из коробки может импортировать из zip архивов!
Загрузка модуля с проверкой есть ли он в системе:

from importlib.util import find_spec

if find_spec("_useful_speedups"):
import _useful_speedups as useful
else:
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
Оператор assert вызывает raise AssertionError, если предикат вернул False
Дескриптор - экземпляр класса, реализующий протокол дескрипторов (методы __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 42

a = A()
a.f

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