Читаем Автостопом по Python полностью

Декораторы, основанные на классах (питонский способ использовать динамическую типизацию)

Werkzeug применяет утиную типизацию для того, чтобы создать декоратор @cached_property. Когда мы говорили о свойстве, описывая проект Tablib, то упоминали, что оно похоже на функцию. Обычно декораторы являются функциями, но поскольку тип ничем не навязывается, они могут быть любым вызываемым объектом: свойство на самом деле является классом. (Вы можете сказать, что оно задумывалось как функция, поскольку его имя не начинается с прописной буквы, а в PEP 8 говорится, что имена классов должны начинаться c прописной буквы.) При использовании нотации, похожей на вызов функции (property()), будет вызван метод property.__init__() для инициализации и возврата экземпляра свойства — класс, для которого соответствующим образом определен метод __init__(), работает как вызываемая функция. Кря.

В следующем фрагменте кода содержится полное определение свойства cached_property, которое является подклассом класса property. Документация класса cached_property говорит сама за себя. Когда это свойство будет использоваться для декорирования BaseRequest.form в коде, который мы только что видели, instance.form будет иметь тип cached_property и с точки зрения пользователя будет вести себя как словарь, поскольку для него определены методы _get_() и __set__(). При получении доступа к BaseRequest.form в первый раз он считает данные формы (если она существует), а затем запишет их в instance.form.__dict__, чтобы к ним можно было получить доступ в дальнейшем: class cached_property(property):

"""Декоратор, который преобразует функцию в ленивое свойство.

Обернутая функция в первый раз вызывается для получения результата,

затем полученный результат используется при следующем обращении к value::

class Foo(object):

@cached_property

def foo(self):

# выполняем какие-нибудь важные расчеты

return 42

Класс должен иметь '__dict__' для того, чтобы это свойство работало.

"""

# деталь реализации: для подкласса, встроенного

# в Python свойства-декоратора

# мы переопределяем метод _get_ так, чтобы получать кэшированное

# значение.

# Если пользователь хочет вызвать метод _get_ вручную, свойство будет

# работать как обычно, поскольку логика поиска реплицируется

# в методе _get_ при вызове вручную.

def __init__(self, func, name=None, doc=None):

self.__name__ = name or func.__name__

self.__module__ = func.__module__

self.__doc__ = doc or func.__doc__

self.func = func

def __set__(self, obj, value):

obj.__dict__[self.__name__] = value

def _get_(self, obj, type=None):

if obj is None:

return self

value = obj.__dict__.get(self.__name__, _missing)

if value is _missing:

value = self.func(obj)

obj.__dict__[self.__name__] = value

return value

Взглянем на этот код в действии:

>>> from werkzeug.utils import cached_property

>>>

>>> class Foo(object):

... @cached_property

... def foo(self):

... print("You have just called Foo.foo()!")

... return 42

...

>>> bar = Foo()

>>>

>>> bar.foo

You have just called Foo.foo()!

42

>>> bar.foo

42

>>> bar.foo # Обратите внимание, сообщение не выводится снова...

42


Response.__call__

Класс Response собран с помощью функциональности класса BaseResponse, как и Request. Мы изучим его интерфейс и не будем смотреть на сам код. Взглянем лишь на строку документации для класса BaseResponse, чтобы узнать, как его использовать.

В примере, показанном в строках документации, функция index() вызывается в ответ на запрос HTTP. Ответом будет строка Index page.

Эта сигнатура нужна в приложениях WSGI, как указано в PEP 333/PEP 3333.

Класс Response является подклассом BaseResponse, поэтому ответ представляет собой объект класса BaseResponse.

Для ответа 404 требуется лишь установить значение ключевого слова status.

И вуаля — объект response является вызываемой функцией сам по себе, все сопутствующие заголовки и детали имеют разумные значения по умолчанию (либо переопределены, если путь отличается от /).

Как объект класса может быть вызываемой функцией? Дело в том, что для него был определен метод BaseRequest.__call__. В следующем примере кода мы покажем лишь этот метод.

Эта сигнатура позволяет сделать объекты класса BaseResponse вызываемыми функциями.

Здесь учтены требования к вызову приложений WSGI для функции start_response.

А здесь возвращается итерабельный объект типа bytes.

Пора извлечь следующий урок: если язык позволяет что-то сделать, почему бы не сделать это? После того как мы поняли, что можно добавить метод __call__() к любому объекту и сделать его вызываемой функцией, мы можем вернуться к оригинальной документации и еще раз перечитать раздел о модели данных в Python (http://docs.python.org/3/reference/datamodel.html).


Примеси (еще одна отличная штука)

Перейти на страницу:

Похожие книги

Из жизни попаданцев
Из жизни попаданцев

Уважаемые читатели! Этот фанфик не пропагандирует идеи национал-социализма и идеалы СС. Автор считает, что лучше всего в непривычный мир может вписаться разведчик или диверсант. Учитывая начало фика, лучшим кандидатом на роль главного героя оказался немец. Автор много читал про диверсантов времен ВМВ. Образ главного героя собирательный, автор использовал факты биографии некоторых друзей и подчиненных Отто Скорцени. Если по каким-либо причинам такой главный герой является для вас неприемлемым, то, убедительная просьба, ПРОСТО НЕ ЧИТАЙТЕ.Ну, а для тех, кто всё-таки решился... В 1945 году Дамблдор и Гриндевальд проводили некий ритуал. Ритуал сорвал офицер СС… «Внизу у лестницы обнаружился еще один труп. Его унесли вместе с трупом красноглазого. Насколько я понял, это был хозяин дома и муж Лили, а также отец маленького Гарри, некий Джеймс Поттер. Честно говоря, я даже обрадовался этому обстоятельству. Во-первых, муж точно заметил бы, что с женой что-то не так, а во-вторых, только мужа мне и не хватало. В-третьих, в гостиной обнаружилась газета со странными движущимися картинками. А на газете была дата… 31 октября 1981 года…»Да-да, мать маленького Гарри осталась жива. Чудом уцелела. Вот, только...

Алексей Бухтояров , Заязочка , Заязочка

Неотсортированное / Фанфик / Попаданцы