Таня Шлюссер - Автостопом по Python
- Название:Автостопом по Python
- Автор:
- Жанр:
- Издательство:Питер
- Год:2017
- Город:СПб.
- ISBN:978-5-496-03023-6
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Таня Шлюссер - Автостопом по Python краткое содержание
и содержит наработки многочисленных профессионалов и энтузиастов, знающих, что такое Python, и чего вы от него хотите. Проверенные методы и новейшие приемы, собранные в этой книге, помогут вам стать профессиональным Python-программистом и во всеоружии встретить наступающую эпоху Python 3.
Автостопом по Python - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
В обоих примерах используется возможность вызвать объекты, которые не являются функциями: вызов cached_property.__init__() позволяет проинициализировать экземпляры класса, чтобы их можно быть применять как обычные функции, а вызов Response.__call__() позволяет объекту класса Response вызвать как функцию самого себя.
В последнем фрагменте используется реализация некоторых классов-примесей (каждый из них определяет какую-либо функциональность в объекте класса Request), характерная для Werkzeug, чтобы продемонстрировать, что такие классы — это тоже отличная штука.
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 собран с помощью функциональности класса 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, вы можете реализовать множественное наследование. Это означает, что парадигма, при которой создаются подклассы для полдюжины разных классов одновременно, — это один из способов разбить функциональность на отдельные классы. Это похоже на пространства имен.
Читать дальшеИнтервал:
Закладка: