Переменные, типы, структуры данных
четыре контейнера, из которых собрано почти всё
Что это
Почти любые данные в программе лежат в одной из четырёх структур: словарь, список, кортеж или множество. Зная, чем они отличаются, читаешь код гораздо быстрее — по одному виду скобок понятно, что происходит.
Отдельно разберём аннотации типов (text: str): они в коде от ИИ встречаются
постоянно и читаются проще, чем кажутся.
Как выглядит в коде
user = {"id": 7, "name": "Ola", "cities": ["Tønsberg", "Oslo"]}
print(user["name"])
print(user.get("email"))
print(user.get("email", "не указан"))
cities = user["cities"]
cities.append("Bergen")
print(user["cities"]) # изменился и оригинал
point = (59.27, 10.41)
lat, lon = point
print(lat, lon)
seen = {"Oslo", "Bergen", "Oslo"}
print(sorted(seen), len(seen))Вывод:
Ola
None
не указан
['Tønsberg', 'Oslo', 'Bergen']
59.27 10.41
['Bergen', 'Oslo'] 2Четыре структуры
| Вид | Скобки | Для чего | Признак в коде |
|---|---|---|---|
| Словарь | {"ключ": значение} | данные с именами полей | обращение x["name"] |
| Список | [1, 2, 3] | упорядоченный набор | обращение по номеру x[0], .append() |
| Кортеж | (1, 2) | набор, который не меняют | распаковка a, b = x |
| Множество | {1, 2, 3} | уникальные значения | проверка if x in seen |
Фигурные скобки означают и словарь, и множество — различить легко: если внутри есть двоеточия, это словарь.
Две строки, которые надо заметить
print(user.get("email")) # None
print(user.get("email", "не указан"))user["email"] при отсутствии ключа падает с KeyError. user.get("email")
возвращает None молча. Разница принципиальная и постоянно встречается в коде
от ИИ: .get() — частый способ «починить» ошибку, спрятав её (статья 2.14).
cities = user["cities"]
cities.append("Bergen")
print(user["cities"]) # ['Tønsberg', 'Oslo', 'Bergen']cities — не копия, а то же самое. Списки и словари передаются по ссылке:
изменил один — изменились оба. Это источник целого класса ошибок, которые
выглядят как магия.
Аннотации типов
def add_reminder(user_id: int, text: str) -> int:Читается слева направо: user_id — целое число, text — строка, функция
возвращает целое число. Это подсказка для читателя, а не проверка: Python
аннотации не навязывает, и передать строку вместо числа ничто не помешает.
Расшифровка того, что встречается чаще всего:
| Запись | Значит |
|---|---|
str, int, float, bool | строка, целое, дробное, да/нет |
list[str] | список строк |
dict[str, int] | словарь: ключи-строки, значения-числа |
str | None | строка или ничего |
-> None | функция ничего не возвращает |
Запись str | None особенно полезна при чтении: она прямо предупреждает, что
результат надо проверять.
Как сказать ИИ
Какие структуры данных используются в этом файле
и что в каждой лежит? Коротко, по строке на переменную.Полезный вопрос, когда данные приходят извне:
Покажи пример данных, которые придут в эту функцию.
Один удачный случай и один с недостающими полями.Когда нужно понять, не изменится ли что-то неожиданно:
Эта функция меняет переданный ей список или создаёт новый?На что смотреть
.get() там, где нужна ошибка. Если поле обязано быть, его отсутствие —
это ошибка, а не повод подставить None. Молчаливый None всплывёт позже и
дальше от причины.
Изменение того, что передали. Функция получила список и добавила в него элемент — снаружи список тоже изменился. Если это не задумано, будут трудные баги.
Словарь вместо понятной структуры. data["result"]["items"][0]["price"] —
признак того, что данные никто не разобрал. Каждое звено здесь может упасть,
и трейсбек покажет только последнее.
Аннотации не соответствуют коду. -> str, а функция иногда возвращает
None. Аннотации ничего не проверяют, поэтому расходиться с кодом могут
незаметно.
Шпаргалка
Четыре структуры: словарь · список · кортеж · множество.
Фигурные скобки с двоеточиями — словарь, без — множество.
x["k"]падает при отсутствии ключа,x.get("k")возвращаетNone.Списки и словари передаются по ссылке: изменил один — изменились оба.
str | Noneв аннотации — результат надо проверять.Аннотации ничего не проверяют, они для читателя.