Пишем каркас приложения

Итак, накидывать функционал можно по-разному. Есть множество подходов. Например, есть TDD, Test Driven Development, согласно которому надо сначала написать много-много тестов, они все сначала падают с ошибками, а потом просто постепенно мы пишем код, который заставляет эти тесты постепенно работать.

Мы по TDD сейчас не пойдём и тесты писать не будем, но в целом можете иметь в голове такой подход. Мы начнём постепенно с реализации, думая каждый раз, в каком слое должна лежать реализуемая сейчас функция или класс.

Файл weather:

#!/usr/bin/env python3.10
from coordinates import get_gps_coordinates
from weather_api_service import get_weather
from weather_formatter import format_weather


def main():
    coordinates = get_gps_coordinates()
    weather = get_weather(coordinates)
    print(format_weather(weather))


if __name__ == "__main__":
    main()

То есть фактическая реализация логики будет инкапсулирована, то есть заключена в отдельные Python-модули coordinates, weather_api_service и weather_formatter, а модуль weather будет просто точкой входа в приложение, запускающей логику.

Обратите внимание — при таком подходе у нас изначально не получится ситуации, что вся логика написана в одной каше, например, вообще без функций или в одной длинной километровой функции. Мы подумали о слоях нашего приложения, для каждого слоя создали отдельное место, в нашем случае Python-модуль, но впоследствии можно расширить до Python-пакета, и теперь будем создавать функции, в которые ляжет бизнес-логика нашего приложения.

Файл coordinates.py:

def get_gps_coordinates():
    """Returns current coordinates using MacBook GPS"""
    pass

И вот тут было бы неплохо подумать, какой формат данных вернёт эта чудесная функция. Она очевидно должна вернуть координаты. Координаты это широта и долгота, то есть два числа. Какие есть варианты?

Самый простой вариант — просто tuple с двумя float числами:

def get_gps_coordinates() -> tuple[float, float]:
    """Returns current coordinates using MacBook GPS"""
    pass

Так, хорошо... А широта это нулевой элемент кортежа, а долгота это первый элемент, да? Или наоборот? Насколько хорошо, что приходится додумывать или читать внутренний код функции, чтобы понять, что она возвращает? В этом нет ничего хорошего. Надо явным образом прописать тип, чтобы разночтений не было и все типы были понятны по сигнатуре функции.