LANG·I Язык Глава 6 из 65

Списки

Ночное дежурство сейсмолога: каталог USGS из 19 073 землетрясений и сильнейший толчок за четырнадцать лет. Учимся держать тысячи значений под одним именем, резать их, сортировать — и не попадаться в ловушку двух имён у одного списка.

С нуля 55 минут Python Программирование Практика

Опирается на: 05 · Свои слова

Что вы унесёте из главы

  • держать тысячи значений под одним именем: индексы, срезы, добавление и удаление
  • находить в данных максимум, среднее, медиану и десятку сильнейших без электронной таблицы
  • понимать, когда два имени смотрят на один список, и делать независимые копии

Прошлая глава кончилась вопросом. Функция умеет проверить на простоту одно число, а по алгоритму Луна — один номер карты. А если чисел тысяча? Этой ночью их будет девятнадцать тысяч, и за каждым стоит землетрясение, которое записали сейсмографы.

Представьте ночную смену в центре сейсмических наблюдений. Таких центров в мире десятки: круглые сутки они принимают записи сейсмографов, определяют, где и насколько сильно тряхнуло, и рассылают сводки. Дежурный живёт по всемирному времени UTC: землетрясению всё равно, какой часовой пояс у ближайшего города, а сводки из разных стран должны складываться в одну ленту. Наша смена — ночь на 30 июля 2025 года по UTC. Что случится в 23:24, вы пока не знаете.

У дежурного под рукой каталог Геологической службы США (USGS): все землетрясения магнитудой 5 и выше с 2015 по 2025 год, 19 073 строки. Он лежит в песочнице курса, и каждая ячейка этой главы может его прочитать. За смену мы ответим на вопросы, которые задают дежурному, — что было, где, насколько сильно, — и по дороге освоим структуру данных, без которой в Python не обходится почти ни одна программа.

22:00. Приём смены

Сменщик оставил журнал за сутки 29 июля: девять толчков. Три слабых у острова Маккуори, между Австралией и Антарктидой, один в Красном море, один у Андаманских островов, два глубоко под Фиджи и два — полчаса назад — в Гватемале. Магнитуды по порядку времени: 5,4; 5,1; 5,1; 5,2; 5,0; 5,8; 6,6; 5,6; 5,7.

С тем, что вы знаете, их пришлось бы держать в девяти переменных: m1 = 5.4, m2 = 5.1 и так до m9. Среднее — сумма девяти имён, выписанных вручную. Завтра толчков будет другое число, и программу придётся переписывать. А цикл из главы 4 по таким переменным не пройдёт: m1 и m2 для Python два разных имени, никак между собой не связанных.

Нужна одна вещь, в которой лежат все значения по порядку. Это список: значения через запятую в квадратных скобках.

Значения внутри списка называют элементами, а номер элемента — индексом. Индексы в Python начинаются с нуля: первый толчок — mags[0], седьмой — mags[6]. Индекс удобнее понимать как расстояние от начала: до первого элемента ноль шагов, до седьмого — шесть. В главе 14 вы увидите, что машина так и считает: адрес элемента в памяти — начало списка плюс индекс, умноженный на размер ячейки.

Из нуля в начале следует правило, о которое спотыкается каждый новичок: в списке из девяти элементов последний индекс — восемь. Запрос mags[9] кончается ошибкой IndexError с пояснением list index out of range — «индекс за пределами списка». Отрицательные индексы считают с конца: mags[-1] — последний элемент, mags[-2] — предпоследний. Получается, что у каждого элемента два адреса.

Срезы

Дежурного спрашивают: «Что было за последние три сообщения?» Можно выписать mags[6], mags[7], mags[8], но для кусков списка есть запись короче — срез. mags[2:7] — элементы с индекса 2 до индекса 7, не включая седьмой. Это та же полуоткрытая граница, что у range(2, 7): длина куска — разность границ, а два соседних среза mags[:5] и mags[5:] стыкуются без зазора и без нахлёста. Пропущенное начало значит «с самого начала», пропущенный конец — «до самого конца»: последние три — это mags[-3:]. Третье число задаёт шаг: mags[::2] — каждый второй.

Журнал за 29 июля. Над ячейками — индексы от начала, под ними — от конца. Тяните ручки под лентой, чтобы выбрать срез; нажмите на ячейку, чтобы получить один элемент. Ячейка «?» — то, чего в списке нет.

Из-за границ срез с ошибкой не падает: если они вышли за список, Python молча обрежет их по краю, а если начало правее конца, вернёт пустой список []. И ещё одно свойство пригодится нам ближе к утру: срез всегда строит новый список, а исходный не трогает.

23:05. Журнал растёт

В 23:05 приходит сообщение из Гватемалы: ещё один толчок, M 5,2. Список умеет расти: mags.append(5.2) дописывает значение в конец. Запись через точку — значение, точка, имя функции — означает «попроси сам список сделать это». Такие функции, приписанные к типу значения, называют методами; подробно о них — в главе 12, а пока достаточно знать, что у списка их около дюжины.

В 23:24:52 начинается то, ради чего вообще существуют дежурства. Первая оценка USGS — магнитуда 8,0 у восточного берега Камчатки. Когда записи придут со станций всего мира, USGS поднимет её до 8,8. Дежурный исправляет запись на месте: присваивание по индексу заменяет элемент.

Последняя строка — проверка «есть ли такое значение в списке»: оператор in отвечает True или False. Чтобы ответить, Python перебирает список с начала, элемент за элементом, пока не найдёт. На девяти элементах это мгновенно, на миллионе уже заметно. В главе 8 появится структура, где in не перебирает элементы и на миллионе так же быстр, как на десятке, а как она это делает, расскажет глава 16.

Бывает и так, что сообщение приходит с опозданием или дважды — от двух агентств об одном событии. Для этого у списка есть insert(i, x) — вставить x так, чтобы он получил индекс i, и pop(i) — вынуть элемент с индексом i и вернуть его; pop() без аргумента вынимает последний. Следите за соседями: при вставке все элементы правее сдвигаются, и их индексы растут на единицу.

Та же лента на вкладке «Изменения». Выберите ячейку — это индекс i, впишите x и нажмите действие. Сдвинувшиеся элементы подсвечиваются: сравните insert(0, x) с append(x).

Вставка в начало заставляет переехать весь список, дописывание в конец не двигает никого. Пока элементов десяток, разницы не видно. В главе 14 мы измерим её на миллионе элементов и узнаем, почему append почти всегда быстрый.

И запомните: список меняется на месте. После append это тот же самый объект, только длиннее. С числами и строками так не бывает — их нельзя изменить, только заменить другими. В главе 2 из-за этого Грейс неожиданно оказалась в двух экипажах сразу. Списки, которые умеют меняться, называют изменяемыми, и ближе к утру это свойство устроит нам неприятность.

23:24. Толчок

На Камчатке 11:24 утра. Толчок в 8,8 — сильнейший на Земле с 2011 года, когда землетрясение магнитудой 9,1 у берегов Японии вызвало цунами и аварию на АЭС «Фукусима-1». По оценке USGS он делит шестое место среди всех землетрясений, записанных приборами. Цунами разошлось по всему Тихому океану, но оказалось слабее, чем боялись, а разрушения для толчка такой силы были небольшими: на Камчатке строят с расчётом на землетрясения. В 1952 году почти на этом же месте было землетрясение магнитудой около 9.

За первый час после главного толчка каталог прибавил больше трёх десятков записей сильнее пятёрки у Камчатки — афтершоки, повторные толчки, которые разломившаяся плита выдаёт ещё месяцами. За первые сутки после главного толчка их набралось больше полутора сотен, а 30 июля 2025 года по UTC стало самым насыщенным днём во всём каталоге: 143 записи. Вручную такие ряды не ведут, но пока в журнале одиннадцать значений, ответим на первые вопросы.

Четыре встроенные функции работают со всем списком сразу: len — длина, max и min — наибольший и наименьший элементы, sum — сумма. А цикл for m in mags проходит по элементам по очереди: на каждом шаге имя m привязано к очередному значению. Внутри — знакомый по главе 4 накопитель. Нажмите «Шаги» и проследите, как растёт total. Растёт он неравномерно: десять толчков из одиннадцати почти ничего не добавят.

Девяносто девять и девять десятых процента энергии суток пришлись на один толчок. Почему формула именно такая — 10 ** (1.5 * m), — объясняет история самой шкалы.

На логарифмической шкале прибавить единицу значит умножить. Магнитуда 6 качает стрелку сейсмографа в десять раз сильнее, чем 5, а 7 — в сто раз. С энергией разница ещё больше: каждая единица магнитуды — примерно в 32 раза больше энергии, потому что $10^{1{,}5} \approx 31{,}6$. Гутенберг и Рихтер связали их формулой $\lg E = 1{,}5\,M + 4{,}8$, где энергия $E$ в джоулях. Поэтому в нашей программе энергия пропорциональна $10^{1{,}5 M}$. Толчок 8,8 сильнее толчка 5,8 не в полтора раза, как кажется по цифрам, а в $10^{4{,}5}$ — примерно в 30 тысяч раз.

Сколько толчков магнитудой 6 нужно, чтобы выделить столько же энергии, сколько один толчок магнитудой 8?

Разница в две единицы магнитуды — это $10^{1{,}5 \cdot 2} = 10^3$: тысяча толчков по 6. А по размаху записи на сейсмографе — всего в сто раз. Логарифмические шкалы обманывают интуицию: «8 против 6» звучит скромно.

00:30. Каталог

Камчатка продолжает выдавать по толчку каждые две-три минуты, и дежурный бросает журнал: дальше работаем с каталогом. Он лежит в файле /data/quakes.csv. Формат CSV (comma-separated values, «значения через запятую») — самый простой способ хранить таблицу текстом: одна строка — одна запись, поля разделены запятыми, а в первой строке названия столбцов.

Время, широта, долгота, глубина в километрах, магнитуда, тип магнитуды и описание места. Разрезать строку по запятым умеет метод строк split. Но в описании места тоже бывает запятая, и тогда оно разваливается на два поля. Поэтому CSV берёт такие поля в кавычки, но разрез по запятым о кавычках ничего не знает.

Первый вызов разрезал по всем запятым, и место развалилось. Во втором мы попросили сделать не больше шести разрезов: первые шесть полей отделились, а всё остальное, вместе с запятой внутри кавычек, осталось седьмым куском. Нам повезло, что место — последний столбец. В общем случае кавычки бывают в любом поле, и для этого в Python есть модуль csv; со строками подробно будем работать в следующей главе. Вот функция, которая читает весь каталог.

Строку за строкой: open открывает файл, readline съедает строку заголовков, цикл for line in file проходит по остальным. Метод strip отрезает перевод строки в конце, split(",", 6) режет на семь кусков, а float превращает текст вроде "8.8" в число. Из каждой строки получается одна запись, и записана она в круглых скобках.

Вопросительные знаки в названии иранского города — не ошибка нашей программы. При выгрузке каталога буквы с диакритикой, вроде ī и ā в слове Fīrūzābād, превратились в «?». Живые данные почти всегда немного грязные, и первым делом аналитик просматривает их глазами. Почему буквы теряются при пересылке, станет понятно в главе 28.

Кортежи

Значения в круглых скобках через запятую — это кортеж. Он похож на список: у него есть длина, индексы, срезы, по нему можно пройти циклом. Отличие одно: кортеж нельзя изменить — ни дописать элемент, ни удалить, ни заменить.

Первая строка теперь короче: ту же функцию load_quakes мы положили в модуль курса, чтобы не переписывать её в каждой ячейке. Дальше — распаковка: справа кортеж из семи значений, слева семь имён, и каждое привязывается к своему значению. В главе 2 вы уже видели её в обмене a, b = b, a: там справа тоже был кортеж, только без скобок.

Кортеж и список различаются назначением. Список — коллекция однородных вещей, которая растёт и убывает, вроде толчков за ночь. Кортеж — одна запись с постоянным набором полей: у землетрясения всегда семь полей, и пятое — всегда магнитуда. Менять в нём нечего, а неизменяемость защищает от случайной порчи; кроме того, как выяснится в главе 8, кортеж может служить ключом словаря. Неудобство тоже видно сразу: q[4] ничего не говорит о том, что это магнитуда. Поля с именами появятся в главе 8, а пока держим в голове: 0 — время, 1 — широта, 2 — долгота, 3 — глубина, 4 — магнитуда, 6 — место.

Срезы работают на каталоге так же, как на журнале.

Карта из точек

У каждого толчка есть широта и долгота, и этого хватит, чтобы нарисовать карту. Соберём их в два списка и отдадим библиотеке рисования matplotlib, которую вы видели в главе 0: scatter ставит точку для каждой пары координат.

Мы не рисовали ни одного материка — только точки эпицентров. А карта мира проступает сама: западный берег обеих Америк, дуги Алеутских и Курильских островов, Япония, Индонезия, извилистый шов посреди Атлантики. Землетрясения идут по границам литосферных плит, там, где плиты расходятся, сталкиваются или трутся боками. Кольцо вокруг Тихого океана — «огненное кольцо», вдоль которого случается большая часть сильных толчков.

Ниже та же карта, только живая. Её данные загружаются прямо в браузер, поэтому ползунки работают мгновенно. Цвет показывает глубину очага, размер — магнитуду.

19 073 толчка M5+ за 2015–2025 годы. Нажмите на точку, чтобы узнать, что это за толчок. Над картой — сводка по тому, что сейчас видно: число толчков, сильнейший, средняя магнитуда и суммарная энергия в долях землетрясения в Вальдивии (о нём — ниже).

Оставьте только глубокие толчки, глубже 300 километров, — их окажется на удивление мало, и лежат они полосами в стороне от океанских жёлобов: под Японским и Охотским морями, под Фиджи, под серединой Южной Америки. Там океанская плита уходит под соседнюю и, погружаясь, продолжает ломаться на глубине до 700 километров. Самый глубокий толчок каталога — 670,8 километра под Фиджи в сентябре 2018 года. Сдвиньте нижнюю границу магнитуды к 7, и останется полторы сотни точек, почти все на огненном кольце.

Карта следит и за ячейками этой главы. Каждый толчок, который ячейка ниже напечатает — целым кортежем или хотя бы со временем, — загорится на ней, а под ячейкой появится ссылка к карте.

01:30. Самое сильное

Звонят из редакции новостей: правда ли, что это сильнейшее землетрясение за десять лет? Ответ лежит в каталоге. Найдём самый сильный толчок так же, как в главе 4 искали максимум: будем держать «лучшего на сейчас» и сравнивать с ним каждого следующего.

Цикл нашёл камчатский толчок — 8,8, сильнейший за все одиннадцать лет. А max(quakes) вернул что-то странное: шестёрку у берегов Японии 31 декабря 2025 года. Встроенная max не знает, что нас интересует магнитуда. Она сравнивает кортежи поэлементно, как слова в словаре: сначала первые элементы, при равенстве — вторые и так далее. Первым элементом стоит время, строки времени сравниваются по алфавиту — а у нас формат «год-месяц-день», и по алфавиту побеждает самая поздняя дата. Ошибки нет, ответ верный, только на другой вопрос. Как сказать max, по какому полю сравнивать, вы узнаете в главе 10.

В списке pairs три кортежа: (5.2, "Гватемала"), (8.8, "Камчатка") и (8.8, "Аляска"). Что вернёт max(pairs)?

Первые элементы 8,8 и 8,8 равны, поэтому решают вторые: строка «Камчатка» больше строки «Аляска», ведь «К» стоит в алфавите позже. Такое сравнение «как в словаре» называют лексикографическим.

Сильнейшее за одиннадцать лет — но не сильнейшее в истории.

Сравним Вальдивию с нашим каталогом. Сложим энергию всех 19 073 толчков за одиннадцать лет и поделим на энергию одного землетрясения 1960 года.

Все землетрясения планеты сильнее пятёрки за одиннадцать лет вместе дали меньше трети того, что Вальдивия выделила за десять минут. А сама Камчатка-2025 — больше четверти всей энергии каталога. Так работает логарифмическая шкала: тысячи средних толчков почти ничего не весят рядом с одним гигантом. Это видно и по сводке над картой: сдвиньте ползунок магнитуды к 6, и толчков останется в тринадцать раз меньше, а энергия упадёт с 32 до 31 процента Вальдивии.

02:30. Середина и десятка

Утром у начальника будут два вопроса: какой толчок «типичный» и какие десять сильнейших. Среднее арифметическое для первого вопроса плохо подходит: его тянут вверх редкие гиганты. Надёжнее медиана — значение, которое оказывается посередине, если выстроить все по порядку. Порядок наводит функция sorted.

Среднее 5,33, медиана 5,2: больше половины толчков каталога — у самого его порога. Последняя строка показывает, что исходный список остался прежним: sorted построил новый. У списков есть и второй способ — метод mags.sort(). Он сортирует сам список, на месте, и ничего не возвращает. Поэтому новички часто попадаются на ordered = mags.sort(): в ordered попадает значение None, «ничего». Запомнить легко: sorted(x) — «дай мне отсортированную копию», x.sort() — «отсортируй сам себя». Обоим можно сказать reverse=True, чтобы получить порядок по убыванию.

Теперь десятка сильнейших. Отсортировать кортежи каталога как есть нельзя: sorted, как и max, сравнит их по времени. Но мы уже знаем, как кортежи сравниваются, — по первому элементу. Значит, достаточно переложить каждую запись в новый кортеж, где магнитуда стоит первой.

Распаковка работает прямо в заголовке цикла: for time, lat, … in раскладывает каждый кортеж по именам. После сортировки по убыванию остаётся взять срез [:10]. Под ячейкой появилась ссылка: все десять толчков уже отмечены на карте эпицентров. Пять из десяти — у берегов Америки, от Аляски до Чили, остальные — на западе Тихого океана и один в Южной Атлантике.

И ещё один вопрос, который сейсмологи задают каталогу первым делом: как часто бывают толчки разной силы? Заведём список из четырёх счётчиков — для магнитуд 5, 6, 7 и 8 — и будем использовать магнитуду как индекс: int(5.8) отбрасывает дробную часть и даёт 5, минус пять — индекс 0.

Почти восемнадцать тысяч пятёрок, тысяча с лишним шестёрок, полторы сотни семёрок и восемь восьмёрок: с каждой единицей магнитуды толчков примерно в десять раз меньше. Эту закономерность в 1944 году описали те же Гутенберг и Рихтер, и она носит их имя. Отношения гуляют от 9 до 18 раз, потому что восьмёрок всего восемь, а на таких малых числах случайность заметна. Вместе с подсчётом энергии из прошлого раздела получается вывод, на котором держится инженерная сейсмология: частые слабые толчки почти ничего не весят, а считаться приходится с редкими сильными.

04:00. Сменщик

Под утро приходит сменщик, чтобы готовить сводку. Ему нужен список ночных толчков по силе. Он берёт журнал смены и пишет три строки.

Отчёт отсортирован, а журнал, который должен был идти по порядку времени, испорчен. С этим вы уже сталкивались в главе 2: присваивание report = night ничего не копирует. Оно вешает второй ярлык на тот же самый список, и sort, вызванный через любое из имён, меняет единственный существующий список. Оператор is подтверждает: это один объект. Нажмите «Шаги»: стрелки от обоих имён ведут в одну точку.

Копия — это новый список с теми же элементами. Её дают полный срез night[:], функция list(night) и метод night.copy(); все три делают одно и то же.

«Это один и тот же объект?» и «у них одинаковое содержимое?» — разные вопросы. Первый задаёт is, второй ==. Сразу после копирования report == night было бы True, а report is night — False.

Самое коварное место — функции. Параметр функции — это тоже ярлык, и при вызове он вешается на тот же объект, что и аргумент. Функция, которая «для себя» сортирует полученный список, портит его тому, кто её вызвал.

Лекарство — не менять то, что вам дали: sorted(mags, reverse=True)[:3]. Хорошая функция возвращает результат и не трогает аргументы; в главе 5 такие функции называли чистыми. Ниже пять сценариев на одной схеме: прежде чем увидеть вывод, предскажите его.

Слева — программа, справа — память: ярлыки-имена и списки, на которые они указывают. Нажимайте «шаг». Перед строкой с print схема спросит, что будет напечатано.

Присваивание = перевешивает ярлык и никогда ничего не копирует. Методы вроде append, sort, pop меняют сам список, и это изменение видно через все ярлыки, которые на нём висят. Нужна независимая копия — сделайте её явно: a[:].

05:00. Где трясёт

Последний вопрос смены: где на Земле трясёт чаще всего? Разобьём планету на клетки по 10 градусов: 18 полос по широте, с севера на юг, и 36 по долготе, с запада на восток. Для каждой клетки нужен счётчик, а клеток — таблица 18 на 36. Таблицу удобно хранить как список строк, где каждая строка — тоже список. Элементом списка может быть что угодно, в том числе другой список: grid[row] — строка таблицы, grid[row][col] — клетка в ней.

Широта 90 (Северный полюс) даёт строку 0, широта −90 — строку 17; долгота −180 — столбец 0. Запись [0] * 36 строит список из 36 нулей: умножение списка на число повторяет его содержимое. Картинку рисует функция show_grid из модуля курса: каждый символ — одна клетка. Чем краснее клетка, тем больше в ней толчков. Огненное кольцо видно и здесь, хоть и грубо: клетка в 10 градусов у экватора — квадрат со стороной больше тысячи километров. И больше половины клеток, 339 из 648, за одиннадцать лет не получили ни одного толчка сильнее пятёрки.

Осталось найти самую горячую клетку. Это максимум по таблице, и искать его будем двумя вложенными циклами.

Тысяча пятьдесят четыре толчка за одиннадцать лет в квадрате между 20 и 30 градусами южной широты у линии перемены дат. Здесь сходятся жёлоба Тонга и Кермадек: Тихоокеанская плита уходит под Австралийскую. На севере жёлоба Тонга GPS-измерения, опубликованные в 1995 году, показали сближение плит на 24 сантиметра в год, самую большую скорость из измеренных на планете. На карте эпицентров выше эта клетка — плотная россыпь точек к северу от Новой Зеландии.

Ловушка умножения

Строить таблицу циклом скучно. Раз [0] * 36 повторяет нули, почему бы не повторить и строку: [[0] * 36] * 18? Одна строка вместо трёх, и тут нас догоняет всё, что мы узнали о ярлыках.

Мы прибавили единицу в одну клетку, а она появилась во всех трёх строках. Умножение списка повторяет его содержимое, а содержимое внешнего списка — ярлык на строку. Получилось три ярлыка на один и тот же список-строку. Цикл с append на каждом проходе вычислял [0] * 36 заново и создавал новую строку; умножение создало строку один раз. С нулями внутри строки такой проблемы нет: число нельзя изменить, += 1 вешает на клетку новый объект, и соседние клетки его не видят.

Таблица 18 × 36 по всему каталогу. Переключите способ построения и снова разнесите толчки. В режиме ловушки можно посмотреть, что лежит в памяти: восемнадцать ярлыков на одну строку.

Карта мира, построенная ловушкой, превращается в вертикальные полосы: в каждой клетке оказывается сумма всего столбца, и у Северного полюса «происходят» сотни землетрясений. Трейсбека такая ошибка не даёт, только неправильный ответ, о котором Python молчит, как в последней записи главы 1.

Копия таблицы — тоже ловушка

Срез grid[:] копирует только внешний список: в новом списке лежат те же ярлыки на те же строки. Такую копию называют поверхностной. Измените клетку в копии — она изменится и в оригинале, потому что строка у них общая. Полную, глубокую копию со всеми вложенными списками делает функция copy.deepcopy из модуля copy или цикл, который копирует каждую строку: new.append(row[:]).

06:00. Сдача смены

Смена кончается, и дежурный сдаёт отчёт. Пять задач — те же вопросы, что приходили за ночь, только оформленные функциями, чтобы их можно было задавать любому каталогу. Тесты проверяют и края: пустой список, повторы, огромные входы — и то, не портит ли функция чужой список.

Напишите функцию strongest(quakes). Она получает список толчков — кортежей того же вида, что в каталоге: время, широта, долгота, глубина, магнитуда, тип, место, — и возвращает кортеж самого сильного. Если сильнейших несколько, верните тот, что раньше в списке. Для пустого списка верните None.

Встроенная max(quakes) не подойдёт: она сравнит кортежи по первому полю — времени.

Чем плох начальный best_mag = 0? Магнитуды очень слабых толчков бывают отрицательными: шкала Рихтера логарифмическая, и ноль на ней — не «ничего», а вполне определённый крошечный размах записи. Начните с первого элемента списка.

Строгое > оставляет первого из равных: следующий с той же магнитудой не вытеснит его. Начинать с первого элемента надёжнее, чем с придуманного «очень маленького» числа: первый элемент — заведомо один из кандидатов.

Напишите функцию mean_mag_depth(quakes), которая возвращает кортеж из двух чисел: среднюю магнитуду и среднюю глубину толчков списка. Округлять не нужно. Для пустого списка верните None.

Нужны два накопителя: сумма магнитуд (индекс 4) и сумма глубин (индекс 3). Поделите каждую на len(quakes).

Вернуть кортеж — значит написать два значения через запятую: return a, b. Скобки можно поставить, можно не ставить.

if not quakes — короткая проверка на пустоту: пустой список, как пустая строка и ноль, считается ложью. Для всего каталога получится средняя магнитуда около 5,33 и средняя глубина около 52 км: большинство землетрясений неглубокие.

Напишите функцию top_k(numbers, k), которая возвращает новый список из k наибольших чисел по убыванию. Если чисел меньше k, верните все. И одно условие: список numbers, который вам передали, должен остаться таким, каким был.

Заготовка даёт правильный ответ. Что в ней не так? Запустите её на списке и напечатайте этот список после вызова.

sorted строит новый список, .sort() меняет переданный.

Срез сам справляется с краями: если k больше длины, [:k] вернёт всё, а [:0] — пустой список. Сортировать весь список ради десятки лучших расточительно; в главе 18 появится способ быстрее — куча.

Дежурные сменяются по кругу. Напишите функцию rotate(items, k), которая возвращает новый список, сдвинутый по кругу вправо на k позиций: rotate([1, 2, 3, 4, 5], 2) → [4, 5, 1, 2, 3]. Отрицательное k сдвигает влево, k может быть больше длины списка. Исходный список менять нельзя.

Сдвиг вправо на k — это последние k элементов, а за ними все остальные. Оба куска — срезы.

Сдвиг на длину списка возвращает его в исходное положение, поэтому k можно заменить остатком k % len(items); в Python он неотрицательный и для отрицательных k. А что, если список пустой?

Проверьте край k = 0: items[-0:] — это items[0:], весь список, а items[:-0] — items[:0], пустой. Сумма — весь список, как и нужно. Без проверки на пустоту k % 0 упал бы с ZeroDivisionError. Плюс склеивает два списка в новый, а исходные не меняются.

Напишите функцию second_largest(numbers), которая возвращает второе по величине различное значение: для [5.2, 8.8, 6.3, 8.8] это 6.3, а не 8.8. Если различных значений меньше двух, верните None. Список может быть очень длинным, и менять его нельзя.

Заготовка спотыкается на повторах и на коротких списках. Попробуйте её на [8.8, 8.8] и на [7.0].

Можно пройти по списку один раз, храня два числа: лучшее и второе. Новое число больше лучшего — лучшее переходит во второе. Меньше лучшего, но больше второго — становится вторым. Равное лучшему пропускаем.

Один проход по списку быстрее сортировки, и ничего не копируется. None в начале, вместо «очень маленького числа», означает «пока ничего не видели». Строка first, second = x, first — знакомый по главе 2 обмен: правая часть вычисляется полностью, прежде чем ярлыки перевесятся.

Куда дальше

Смена сдана, но один вопрос остался без ответа: в какой стране трясло чаще всего? Ответ есть в каталоге, в седьмом поле: «125 km SE of Petropavlovsk-Kamchatsky, Russia». Только записан он текстом, и страна в нём — кусок после последней запятой. Чтобы его вырезать, нужно уметь работать со строками. В следующей главе мы займёмся ими всерьёз и соберём из строк собеседника — программу, с которой в 1966 году люди разговаривали о самом личном и которая напугала собственного автора.