Как устроен Python. Как устроен Python. Харрисон. Харрисон Мэтт
Скачать 5.41 Mb.
|
14.10. Упражнения 1. Создайте список, сохраните в нем имена ваших коллег и друзей. Изменился ли идентификатор списка? Отсортируйте список. Ка- кой элемент стоит в начале списка? Какой элемент является вто- рым? 14.10. Упражнения 129 2. Создайте кортеж с вашим именем, фамилией и возрастом. Соз- дайте список people и присоедините к нему свой кортеж. Создайте другие кортежи с соответствующей информацией о ваших друзьях и присоедините их к списку. Отсортируйте список. Когда в книге будут рассмотрены функции, вы сможете использовать параметр key для сортировки списка по любому полю кортежа: имени, фами- лии или возрасту. 3. Создайте список с именами ваших друзей. Создайте список с деся- тью самыми популярными именами. При помощи операций мно- жеств проверьте, входят ли имена кого-либо из ваших друзей в этот список. 4. Посетите сайт проекта «Гутенберг» 1 и найдите страницу текста из Шекспира. Вставьте текст в строку, заключенную в тройные ка- вычки. Создайте другую строку с абзацем текста из Ральфа Уолдо Эмерсона. Используйте метод .split строк для получения списка слов из каждого текста. При помощи операций с множествами най- дите общие слова, встречающиеся в текстах обоих авторов, а также слова, уникальные для каждого автора. 5. Кортежи и списки похожи, но обладают разным поведением. Ис- пользуйте операции с множествами для нахождения атрибутов объекта списка, отсутствующих у объекта кортежа. 1 https://www.gutenberg.org/ 15 Итерации Одна из стандартных идиом при работе с последовательностями — пере- бор содержимого последовательности. Например, вы можете отфиль- тровать один из элементов, применить к элементам функцию, вывести элементы и т. д. Для решения этой задачи можно воспользоваться цик- лом for . В следующем примере выводятся все строки из списка: >>> for letter in ['c', 'a', 't']: ... print(letter) c a t >>> print(letter) t ПРИМЕЧАНИЕ Обратите внимание: конструкция цикла for содержит двоеточие ( : ), за ко- торым следует код с отступом (блок цикла for ). В цикле for Python создает новую переменную letter для хранения текущего элемента. Обратите внимание: в letter хранится не индекс, а строка. Python не очищает переменную после завершения цикла. 15.1. Перебор с индексом 131 15.1. Перебор с индексом В таких языках, как C, перебор в последовательностях ведется не по элементам последовательности, а по индексам. Используя индексы, вы можете извлекать элементы с указанными индексами. Ниже показан один из вариантов решения этой задачи с использованием встроенных функций Python range и len : >>> animals = ["cat", "dog", "bird"] >>> for index in range(len(animals)): ... print(index, animals[index]) 0 cat 1 dog 2 bird Приведенный выше фрагмент содержит код с душком: этот термин обыч- но подразумевает, что вы используете Python не так, как следовало бы. Обычно перебор в последовательностях выполняется для получения доступа к элементам последовательности, а не к индексам. Тем не менее в отдельных случаях индекс тоже бывает нужен. Python предоставля- ет встроенную функцию enumerate , с которой комбинация range и len становится излишней. Функция enumerate возвращает кортеж (индекс, элемент) для каждого элемента в последовательности: >>> animals = ["cat", "dog", "bird"] >>> for index, value in enumerate(animals): ... print(index, value) 0 cat 1 dog 2 bird Так как кортеж содержит пару из индекса и значения, вы можете вос- пользоваться распаковкой кортежа для создания двух переменных, index и value , прямо в цикле for . Имена переменных должны разделять- ся запятой. Если длина кортежа совпадает с количеством переменных, включаемых в цикл for , Python создаст их за вас. 132 Глава 15. Итерации Создание переменной в цикле for [ , , ] Id:4f3b Type:List letter 'c' Str for letter in ['c', 'a', 't']: 'a' Str 't' Str Этап 1: Сначала переменная указывает на c print(letter) Вывод Вывод c [ , , ] Id:4f3b Type:List letter 'c' Str for letter in ['c', 'a', 't']: 'a' Str 't' Str Этап 2: Затем переменная указывает на a print(letter) c a Команда Что делает компьютер Переменные Объекты Рис. 15.1. Создание переменной в цикле for. Создается новая переменная letter; сначала она указывает на символ 'c', который выводится вызовом print. Затем цикл переходит на следующую итерацию, и переменная указывает на 'a' 15.1. Перебор с индексом 133 [ , , ] Id:4f3b Type:List letter 'c' Str for letter in ['c', 'a', 't']: 'a' Str 't' Str Этап 3: Наконец, letter указывает на t, список уничтожается print(letter) Вывод c a t [ , , ] Id:4f3b Type:List letter 'c' Str for letter in ['c', 'a', 't']: 'a' Str 't' Str Этап 4: Символы c и a уничтожаются, символ t остается print(letter) Вывод c a t Рис. 15.2. Цикл for продолжается, а после вывода 't' он завершается. В этот момент литерал списка уничтожается в ходе уборки мусора. Так как на 'c' и 'a' указывает только список, они тоже уничтожаются. Однако переменная letter продолжает указывать на 't'. Python не уничтожает эту переменную, и она продолжит существовать после завершения цикла for 134 Глава 15. Итерации 15.2. Выход из цикла Иногда бывает нужно прервать выполнение цикла преждевременно, до перебора всех элементов в цикле. Ключевое слово break прерывает ближайший внутренний цикл, в котором вы находитесь. Следующая про- грамма суммирует числа до тех пор, пока не обнаружит отрицательное число. В этом случае выполнение цикла прерывается командой break : >>> numbers = [3, 5, 9, -1, 3, 1] >>> result = 0 >>> for item in numbers: ... if item < 0: ... break ... result += item >>> print(result) 17 ПРИМЕЧАНИЕ В строке result += item используется так называемое расширенное присваивание. Эта команда эк- вивалентна: result = result + item Расширенное присваивание выполняется чуть быстрее, так как выборка для переменной result выполняется всего один раз. Кроме того, команда полу- чается более компактной и быстрее вводится. ПРИМЕЧАНИЕ Блок if внутри блока for снабжен отступом из восьми пробелов. Блоки могут быть вложенными, и каждый уровень должен иметь свой отступ. 15.3. Пропуск элементов в цикле Другая стандартная идиома циклов — пропуск отдельных элементов при переборе. Если выполнение тела цикла for занимает некоторое время, а выполняться оно должно только для некоторых элементов последова- 15.5. Удаление элементов из списков при переборе 135 тельности, вам пригодится ключевое слово continue . Команда continue приказывает Python прервать обработку текущего элемента цикла и про- должить цикл от начала блока for со следующим значением в цикле. В следующем примере суммируются все положительные числа из списка: >>> numbers = [3, 5, 9, -1, 3, 1] >>> result = 0 >>> for item in numbers: ... if item < 0: ... continue ... result = result + item >>> print(result) 21 15.4. Оператор in может использоваться для проверки принадлежности Мы использовали команду in в цикле for . В языке Python эта команда также может использоваться для проверки принадлежности. Если вы хотите узнать, содержит ли список заданный элемент, используйте коман ду in для проверки: >>> animals = ["cat", "dog", "bird"] >>> 'bird' in animals True Если вам потребуется узнать индекс, используйте метод .index : >>> animals.index('bird') 2 15.5. Удаление элементов из списков при переборе Как уже упоминалось ранее, списки являются изменяемыми. Изменяе- мость означает, что в них можно добавлять или удалять элементы. Кроме того, списки являются последовательностями, а значит, их содержимое можно перебирать. 136 Глава 15. Итерации Например, если вы захотите отфильтровать список имен так, чтобы в нем остался только элемент 'John' или 'Paul' , делать это так было бы неправильно: >>> names = ['John', 'Paul', 'George', ... 'Ringo'] >>> for name in names: ... if name not in ['John', 'Paul']: ... names.remove(name) >>> print(names) ['John', 'Paul', 'Ringo'] Что произошло? Python предполагает, что списки не изменяются в процессе перебора. Добравшись до 'George' , цикл удаляет имя из списка. Во внутренней реализации Python отслеживает текущий ин- декс цикла for . На этот момент в списке остаются только три элемента: 'John' , 'Paul' и 'Ringo' . Однако цикл for думает, что текущей является позиция с индексом 3 (четвертый элемент), а четвертого элемента не существует, поэтому цикл останавливается, и элемент 'Ringo' остается на месте. Существует два альтернативных решения для удаления элементов из списка в процессе перебора. В первом варианте удаляемые элементы отбираются при первом проходе по списку. Следующий цикл перебира- ет только те элементы, которые подлежат удалению ( names_to_remove ), и удаляет их из исходного списка ( names ): >>> names = ['John', 'Paul', 'George', ... 'Ringo'] >>> names_to_remove = [] >>> for name in names: ... if name not in ['John', 'Paul']: ... names_to_remove.append(name) >>> for name in names_to_remove: ... names.remove(name) >>> print(names) ['John', 'Paul'] 15.7. Циклы while 137 Другое решение — перебор по копии списка. Оно довольно легко реали- зуется конструкцией копирования среза [:] , которая будет рассмотрена в главе, посвященной срезам: >>> names = ['John', 'Paul', 'George', ... 'Ringo'] >>> for name in names[:]: # copy of names ... if name not in ['John', 'Paul']: ... names.remove(name) >>> print(names) ['John', 'Paul'] 15.6. Блок else Цикл for также может содержать блок else . Любой код в блоке else будет выполнен в том случае, если цикл for не достиг команды break Сле дующий пример проверяет, являются ли числа из цикла положи- тельными: >>> positive = False >>> for num in items: ... if num < 0: ... break ... else: ... positive = True Команды continue не влияют на выполнение блока else Имя команды else выглядит несколько странно. Для цикла for она по- казывает, что была обработана вся последовательность. Блок else в цикле for часто применяется для обработки отсутствия элементов. 15.7. Циклы while Python позволяет многократно выполнять блок кода, пока некоторое условие остается истинным. Такая конструкция называется циклом while, а для ее создания используется команда while . За циклом while следует 138 Глава 15. Итерации выражение, результат которого равен True или False , а за выражением идет двоеточие. Помните, что следует за двоеточием ( : ) в Python? Да, блок кода с отступом. Этот блок продолжит выполняться, пока результат выражения остается равным True . В программе может легко возникнуть бесконечный цикл. Бесконечные циклы обычно нежелательны, потому что ваша програм- ма «зависает» в цикле без возможности выхода. Впрочем, у правила есть исключения: например, сервер в бесконечном цикле принимает и обрабатывает запросы. Другое исключение, встречающееся в коде Python более высокого уровня, — бесконечный генератор. Генератор ведет себя как отложенный список, который создает значения только тогда, когда они будут задействованы в переборе. Если вы знакомы с обработкой потоков, генератор можно рассматривать как поток. (Генераторы в этой книге не рассматриваются, но я опишу их в книге более высокого уровня.) Как правило, если у вас имеется объект, поддерживающий перебор, для перебора элементов используется цикл for . Циклы while используются при отсутствии простого доступа к объекту, поддерживающему перебор. Типичный пример использования цикла while — обратный отсчет: >>> n = 3 >>> while n > 0: ... print(n) ... n = n - 1 3 2 1 Для выхода из цикла while также может использоваться команда break : >>> n = 3 >>> while True: ... print(n) ... n = n - 1 ... if n == 0: ... break 15.9. Упражнения 139 15.8. Итоги В этой главе рассматривается использование циклов for для перебора элементов последовательности. Вы видели, что в цикле можно вести перебор по спискам; также возможен перебор по строкам, кортежам, сло- варям и другим структурам данных. Более того, вы можете определять собственные классы, поддерживающие перебор в циклах for , реализуя метод .__iter__ Цикл for создает переменную при переборе. Эта переменная не унич- тожается после цикла, а продолжает существовать. Если цикл for вы- полняется внутри функции, переменная будет уничтожена при выходе из функции. Также в этой главе была представлена функция enumerate . Функция возвращает последовательность кортежей (пар «индекс, значение») для переданной последовательности. Если вам понадобится получить при переборе как индекс, так и значение, используйте enumerate Наконец, вы узнали, как прервать выполнение цикла, перейти к следу- ющему элементу или использовать команду else . Все эти конструкции позволяют адаптировать логику циклов для конкретных задач. 15.9. Упражнения 1. Создайте список с именами друзей и коллег. Вычислите среднюю длину имен в списке. 2. Создайте список с именами друзей и коллег. Проведите поиск име- ни John в списке в цикле for . Если имя не найдено, выведите соот- ветствующее сообщение (подсказка: используйте else ). 3. Создайте список кортежей из имени, фамилии и возраста ваших друзей и коллег. Если возраст неизвестен, занесите значение None Вычислите средний возраст, пропустив все значения None . Выведи- те каждое имя, за которым следует строка Old (возраст выше сред- него) или Young (возраст ниже среднего). 16 Словари Словари (dictionaries) — высокооптимизированный встроенный тип в языке Python. Словарь Python отчасти напоминает обычный словарь, состоящий из слов и определений. Задача словаря — обеспечить быстрый поиск определения по ключевому слову. В обычном словаре для ускоре- ния поиска можно воспользоваться методом бинарного поиска (открыть словарь на середине, определить, в какой половине находится искомое слово, и повторить). Словарь Python тоже состоит из слов и определений, но они называют- ся ключами и значениями соответственно. Цель словаря — обеспечить быстрый поиск по ключу и извлечь значение, связанное с этим ключом. Как и в обычном словаре, в котором нахождение слова по определению займет много времени (если вы заранее не знаете искомое слово), поиск по значению в словаре Python происходит очень медленно. В Python 3.6 у словарей появилась новая особенность: ключи теперь сорти- руются по порядку вставки. Если вы пишете код Python, который должен работать в предыдущих версиях, вы должны запомнить, что до версии 3.6 порядок ключей был произвольным (что позволяло Python выполнять быстрый поиск, но было не особо полезно для конечного пользователя). 16.1. Присваивание в словарях Словари связывают ключ со значением (в других языках программиро- вания они могут называться хешами, хеш-картами, картами или ассо- 16.1. Присваивание в словарях 141 циативными массивами). Допустим, вы хотите сохранить информацию о человеке. Вы уже видели, как использовать кортеж для представления записи. Словари тоже могут использоваться для решения этой задачи. Так как словари встроены в Python, для их создания можно воспользоваться синтаксисом литералов. В следующем словаре хранится имя и фамилия: >>> info = {'first': 'Pete', 'last': 'Best'} ПРИМЕЧАНИЕ Также словарь можно создать при помощи встроенного класса dict . Если передать классу список пар кортежей, он вернет словарь: >>> info = dict([('first', 'Pete'), ... ('last', 'Best')]) При вызове dict также можно использовать именованные параметры: >>> info = dict(first='Pete', last='Best') Если вы используете именованные параметры, они должны быть допустимы- ми именами переменных Python, тогда они будут преобразованы в строки. Для вставки значений в словарь можно воспользоваться индексными операциями: >>> info['age'] = 20 >>> info['occupation'] = 'Drummer' В этом примере ключами являются 'first' , 'last' , 'age' и 'occupation' Например, 'age' — ключ, которому соответствует значение: целое чис- ло 20. Чтобы быстро найти значение, соответствующее 'age' , выполните поиск индексной операцией: >>> info['age'] 20 С другой стороны, если вам потребуется определить, какой ключ со- ответствует значению 20, такая операция будет слишком медленной. В приведенном примере продемонстрирован синтаксис литералов для создания изначально заполненного словаря. Пример также показывает, как квадратные скобки (индексные операции) используются для вставки 142 Глава 16. Словари элементов в словарь и их извлечения. Индексная операция связывает ключ со значением при использовании в сочетании с оператором при- сваивания ( = ). Если индексная операция не содержит присваивания, она находит значение, соответствующее заданному ключу. 16.2. Выборка значений из словаря Как вы уже видели, синтаксис литералов с квадратными скобками может извлечь значение из словаря при использовании квадратных скобок без присваивания: >>> info['age'] 20 Словари Код Что делает компьютер Переменные Объекты { : } Id:4f3b Type:Dict first = 'Peter' Словари не копируют данные info = {'name' : first} first 'Peter' Str info 'name' Str Рис. 16.1. Создание словаря. В данном случае в качестве значения используется существующая переменная. Обратите внимание: словарь не копирует переменную, но создает указатель на нее (увеличивая ее счетчик ссылок) |