0:03
Теперь от теории классов давайте перейдем к практике.
Мы напишем небольшую программку, причем напишем её с нуля,
с самого начала и эта программа будет содержать класс.
Класс будет принимать на вход название города и будет иметь метод,
который будет возвращать прогноз погоды в этом городе.
На самом деле этот класс можно будет расширять бесконечно,
например добавляя ему методы для получения
грядущих событий в вашем любимом городе либо
новостей относящихся к нему.
Давайте начнём.
Первое что мы сделаем, это создадим директорию
в которой будем работать,
перейдем в неё,
создадим virtual land - вы уже умеете это делать.
После того, как виртуальное окружение создастся мы должны его активировать.
Нам понадобятся две сторонние библиотеки для работы нашей программы.
Давайте их установим.
Первая из них это библиотечка requests,
а вторая это Python-dateutil.
Request нам потребуется чтобы делать http запросы,
а Python-dateutil позволит преобразовывать
даты, которые представлены в виде строки в Python'овское представление,
то есть, в объекты модуля datetime.
У нас установились наши библиотеки.
Сейчас я начну программировать
в среде программирования Visual Studio Code
или по другому говоря VSCode.
Это новая для вас среда, возможно многие из вас с ней не знакомы.
Вот собственно сейчас мы с ней и познакомимся.
Внутри VSCode'а мы откроем нашу директорию в которой мы только что
создали виртуальное окружение. Это делается с помощью file - open.
Открываем нашу директорию
и вот она открылась.
Мы видим наше виртуальное окружение.
Следующим шагом мы должны указать, где же находится
интерпретатор Python для нашего проекта.
2:25
Select wordspace interpreter.
Выбираем интерпретатор Python из нашего виртуального окружения.
Внутри нашего проекта мы можем создать файлик.
Назовем его city.py.
Напомню что наша программка будет выдавать прогноз погоды в городе.
Как только мы создали файл, Visual Studio Code
предлагает нам установить linter,
то есть специальные утилиты, которые помогают нам программировать.
В данном случае мы установим linter pep8
чтобы он следил за стилем нашего кода,
а также linter flake8.
Он будет помогать нам находить очевидные ошибки в нашем коде.
Pylint мы не будем устанавливать, но это также замечательный linter.
Теперь мы наконец-то можем программировать.
С чего же нам начать?
Давайте начнем со стандартного шага.
Напишем if __name__ = "__main__" ,
то есть будем запускать нашу программу только тогда,
когда она вызывается напрямую.
А не импортируется.
Внутри этой конструкции вызовем функцию __main__.
Назовем её начиная с символа нижнего подчеркивания, чтобы подчеркнуть
то, что она является приватной и
не должна использоватся из стороннего кода.
Объявим эту функцию.
4:03
Нам нужен класс, который будет принимать на вход имя города.
Давайте начнем программу писать с конца.
То есть не имея ещё класса
объявим скелет нашей программы.
Будем смотреть погоду в Москве.
У экземпляра класса CityInfo будет метод weather_forecast.
4:39
Этот метод вернет нам список
с прогнозом погоды на несколько дней вперед
и последнее, что мы сделаем, это напечатаем его.
Причем напечатаем красиво
и будем для этого использовать модуль стандартной библиотеки
pprint - это pretty print.
Чтобы это заработало, нам конечно же нужно импортировать
модуль pretty print.
Теперь у нас есть код, который мы должны реализовать.
Flake8 подчеркивает нам то, что у нас ещё нет класса CityInfo.
Давайте его создадим.
Class CityInfo.
У него будет переопределен метод __init__, то есть иницализатор класса
и он будет принимать название города.
Устанавливаем атрибут экземпляра.
5:51
который должен возвращать прогноз погоды.
Пока он ничего не будет делать.
Давайте подумаем о том, откуда нам брать прогноз погоды.
В интернете есть замечательный ресурс yahoo weather api,
представляемый компанией Yahoo.
Мы будем пользоваться им.
Перейдем на их сайт и посмотрим
как нам получить прогноз погоды.
Вот в этой формочке мы можем поэкспериментировать с их api.
На самом деле тут уже практически готов правильный запрос.
Нужно только в одном месте поменять
название места, где мы хотим смотреть прогноз погоды, на наш
и указать, что результат мы хотим получать не
в Фаренгейтах, а в Цельсиях, температуру.
Я заранее посмотрел, как это делается, конечно же
и мы можем нажать кнопочку тест и yahoo предоставляет нам
ссылку, по которой мы можем перейти и увидеть
прогноз погоды в Москве.
На самом деле это большой json,
внутри которого есть много вложенных полей.
И прогноз погоды скрыт достаточно глубоко.
Вот он. Мы видим, что здесь несколько объектов
внутри списка по дням.
Здесь есть, например, сегодняшняя дата и так далее.
Наша цель - получить эти данные.
Однако мы не будем просто так писать
код, делающий http-запрос внутри метода weather_forecast.
Мы создадим специальный класс,
который будет называтся YahooWeatherForecast.
7:43
У него будет метод get,
который будет принимать город.
И вот именно этот класс будет ответственный за то,
чтобы ходить по сети и делать запросы к yahoo.
На самом деле чем это хорошо?
А тем что мы этот класс впоследствии сможем подменить другим.
Если вдруг с API Yahoo что-то случится,
у нас всегда будет возможность поменять только один компонент
нашей программы, только один класс заменить
и весь остальной код программы продолжит работать.
Давайте сделаем http-запрос.
У нас в буфере обмена содержится тот url-адрес, который
Yahoo нам предоставил.
Это достаточно длинная строка
и нам нужно в ней заменить название города
moscow
на то что мы получаем в аргументах, на наш city.
По-хорошему эту строку желательно разбить на несколько,
чтобы pep8 linter не ругался,
но так как это пример,
мы этого сейчас делать не будем,
но на практике это нужно сделать.
Теперь мы можем воспользоватся библиотечкой requests.
Давайте сначала её импортируем.
И мы можем получить данные.
Делаем requests.get(url).json
То есть преобразовываем ответ json'а в Python'овское представление.
В данном случае это будет словарь.
Теперь нам нужно достучаться до того вложенного объекта,
который был в этих данных.
Давайте это сделаем.
Напишем, зададим переменную forecast_data,
которая будет равнятся следующему.
Смотрите, у нас внутри этих данных
на верхнем уровне находится словарь query.
Обращаемся к нему.
Дальше внутри query у нас словарь results
10:26
И это список с прогнозом погоды на несколько дней.
Однако он
отдается нам Yahoo и давайте посмотрим.
Здесь дата представлена как строка
и также есть самая максимальная температура за день,
она доступна по ключу high,
мы будем брать дату и вот эту температуру самую максимальную.
Определим словарь forecast
и заполним его данными.
Для этого мы проитерируемся по forecast data,
полученным с Yahoo
и заполним forecast данными, пригодными для нас.
Возьмем дату оттуда,
а также возьмем оттуда самую максимальную температуру за день.
11:36
Что еще хотелось бы здесь сразу сделать, мы видим, что
дата здесь представлена как строка.
Как раз для этого нам пригодится
модуль dateutil, который мы устанавливали в самом начале,
в нем содержится полезная функция parse,
внутри модуля dateutil.parser, внутри пакета
и мы можем ее импортировать и
с помощью ее преобразовать строку, содержащую дату в объект
даты из модуля date time стандартной библиотеки Python.
И в принципе все, мы можем
сделать return forecast
и сохранить.
Теперь мы вернемся к методу экземпляра weather forecast
и в этом методе мы обратимся к yahoo weather forecast классу
и вызовем его метод get для нужного города.
Давайте сделаем,
расширим метод init.
Он ну нас будет принимать
дополнительный параметр необязательный weather forecast
и ставить приватную переменную weather_forecast экземпляру класса.
13:09
Если же мы weather forecast не передали,
будет по умолчанию использоваться Yahoo weather forecast экземпляр.
Теперь мы внутри метода weather forecast можем вызвать
self,
weather forecast, то есть обратиться к приватному атрибуту
и вызвать у него метод get,
передав ему self.city.
13:56
Мы видим, что мы получили
прогноз погоды в Москве,
да, вот высшая температура, самая высокая температура сегодня
это 16 градусов, такое вот холодное лето 2017 года.
Как мы можем улучшить наш код.
Он уже сейчас работает, он достаточно расширяемый,
но мы можем сделать еще лучше.
Давайте
представим, что нашим приложением, которое мы пишем,
пользуется достаточно много пользователей,
и на самом деле приходит множество запросов
о том, чтобы посмотреть прогноз погоды в Москве.
Давайте это сэмулируем.
Например, пусть пришло 5 запросов.
В этот момент, на каждый из 5 запросов
мы будем отсылать
http запрос к Yahoo, для того, чтобы получить прогноз.
Это не очень хорошо, потому что каждый http запрос - достаточно
долгая операция,
давайте посмотрим, как мы можем сделать лучше.
Мы можем расширить
класс YahooWeatherForecast и добавить к нему метод init.
15:15
И создать внутри экземпляра приватных переменных,
которые будут содержать в себе кэш данных по городам.
Кэш представляет собой словарь,
который содержит прогноз погоды в определенном городе,
каждый раз, когда будет вызываться метод get нашего класса
YahooWeatherForecast,
мы будем проверять, что если город находится в словаре,
то мы будем возвращать данные, которые принадлежат этому городу
из этого city кэша.
И каждый раз, когда мы получили данные, мы будем обновлять
приватный словарик, приватный атрибут
и ставить
городу определенный прогноз погоды.
Теперь,
перед тем, как отправить
http запрос, давайте напишем print
sending
http request
и здесь мы вынесем
yahoo weather forecast экземпляр на верхний уровень
17:01
Таким образом все наши экземпляры класса CityInfo
будут переиспользовать вот этот вот экземпляр
YahooWeatherForecast и на самом деле, несмотря на то, что у нас
отправится 5 запросов к прогнозу погоды,
у нас отправится всего лишь один запрос
к Yahoo по http. Давайте в этом убедимся.
Да, sending http request напечаталось только один раз.
Это во-первых и быстрее работает в итоге
и мы экономим на http запросах,
например, это может быть полезно так как api-шки
сторонние часто бывают платными.
В данном примере мы применили композицию классов,
то есть внутри класса CityInfo у нас
атрибуту присвоен другой класс,
часто это очень хороший подход к написанию кода.
В данном примере мы не обрабатывали исключения,
какие здесь они могли быть.
Во-первых сайт Yahoo мог быть недоступен,
во-вторых, каждый раз, когда мы
обращались к ключу словаря мог произойти key error,
то есть ключа такого могло не произойти,
потому что Yahoo вернул нам невалидные данные.
Также когда мы преобразовывали дату из строки
в объект date time, также мог произойти exception.
Вы пока обрабатывать exception не умеете,
но вам осталось узнать о классах совсем немножко
про наследование и после этого мы научим вас
обрабатывать исключения в программах.
В данном случае мы написали класс, который умеет получать информацию
о городе, причем этот класс достаточно поддерживаемый
и его компоненты легко заменяемы. И также он расширяемый.