········# в методе __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).

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

Примеси в Python — это классы, которые предназначены для того, чтобы добавлять определенную функциональность — набор связанных атрибутов. В Python, в отличие от Java, вы можете реализовать множественное наследование. Это означает, что парадигма, при которой создаются подклассы для полдюжины разных классов одновременно, — это один из способов разбить функциональность на отдельные классы. Это похоже на пространства имен.

Подобное разбиение может быть полезно во вспомогательной библиотеке вроде Werkzeug, поскольку она говорит пользователю, какие функции связаны друг с другом, а какие — нет. Разработчик может быть уверен, что атрибуты в одном классе-примеси не будут изменены функциями другого класса-примеси.

В Python для того, чтобы идентифицировать класс-примесь, не нужно ничего, кроме как следовать соглашению, в рамках которого к имени класса добавляется слово «Mixin». Это означает, что, если вы не хотите обращать внимания на порядок разрешения методов, все методы класса-примеси должны иметь разные имена.

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

Все книги серии Бестселлеры O'Reilly

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