List. Работа со списками
Списки в Python — отличный инструмент для работы с наборами значений; арсенал возможностей при работе со списками весьма велик.
Списки — упорядоченные изменяемые коллекции объектов произвольных типов.
- Изменяемые: при изменении числа элементов списка или их значений изменяется сам объект в памяти, а не создаётся новый.
- Упорядоченные: каждому элементу списка присваивается порядковый номер — индекс. По индексу можно получить доступ к значению элемента списка.
Объявить список можно несколькими способами.
Объявление списка функцией list()
Любой итерируемый объект можно преобразовать в список функцией
list()
Скопировать кодPYTHONname_movie = list('Матрица')
print(name_movie)
# Вывод в терминал: ['М', 'а', 'т', 'р', 'и', 'ц', 'а']
# Такая запись создаст пустой список:
movies = list()
print(movies)
# Вывод в терминал: []
Литерал
Литералами
в программировании называют значения, включённые прямо в код программы.
Литерально можно объявить переменную любого встроенного типа:
Скопировать кодPYTHON# Литеральное объявление переменных int и float:
count = 5
proportion = 4.1
# А вот уже не литеральное объявление числа:
summa = count + proportion
# При литеральном объявлении строки последовательность символов замыкают в кавычки:
name = 'Игорь'
title = "McDucken’s"
# А нелитеральным объявлением будет, например, объявление строки через функцию:
proportion_str = str(proportion)
# Литералом для объявления списка будет
# запись элементов через запятую в квадратных скобках
movies = ['Матрица', 'Хакеры', 'Трон']
# Литеральное объявление пустого списка
movie_ratings= []
Списковое включение (List comprehension)
List comprehension — это сокращённая форма записи программного кода, создающая список на основе заданных правил и условий.
Термин List comprehension
иногда переводят как «генератор списков», но этот перевод не совсем
корректен: в Python есть отдельное понятие «генератор», в результате
возникает терминологическая путаница. Распространён перевод «списковое
включение» — он встречается в статьях и в документации. Мы будем
применять английское название.
Напишем код
программы, которая работает с данными из онлайн-кинотеатра и накручивает
рейтинги всем фильмам. На вход программа получает список рейтингов
movie_ratings
, каждой оценке из списка добавляет 0.2 балла и записывает результат в новый список.Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8]
# Объявляем новый список, в него будем складывать измененные оценки
new_movie_ratings = []
# Перебор списка в цикле:
for rating in movie_ratings:
rating += 0.2 # Значение элемента исходного списка увеличивается на 0.2
new_movie_ratings.append(rating) # Значение добавляется в новый список
print(new_movie_ratings)
# Вывод в терминал: [4.9, 5.2, 4.5, 4.0]
# Хм, неловко вышло: накрутили рейтинг так, что получили 5.2 по пятибалльной шкале.
# TODO Ладно, позже починим.
Запись через list comprehension будет гораздо короче:
Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8]
new_movie_ratings = [rating + 0.2 for rating in movie_ratings]
print(new_movie_ratings)
# Вывод в терминал: [4.9, 5.2, 4.5, 4.0]
Выглядит намного лучше: вместо четырёх строк кода получаем всего одну.
Чтобы на выходе получился список — код заключается в квадратные скобки, это литералы списка.
Внутри квадратных скобок можно выделить три части:
- Значение элемента нового списка: значение из исходного списка, увеличенное на 0.2.
- Обрабатываемый объект: переменная, в которую по очереди, как в цикле, передаются значения всех элементов списка:
rating
. - Источник, из которого получаем значения элементов: список
movie_ratings
.
Части отделены друг от друга ключевыми словами
for
и in
.Создайте список целых чисел
1, 4, 9, 16, 25, 36, 49, 64, 81, 100
используя списковое включение. В качестве источника значений используйте range()
КодPYTHON
2
1
numbers = [number*number for number in range(1, 11,)]
2
print(numbers)
Условия в list comprehension
Сейчас программа увеличивает рейтинг фильма на 0.2, даже если он имеет максимальное значение 5.
Чтобы
избежать превышения предельно возможного рейтинга (шкала-то
пятибалльная) в списковое включение можно добавить условие, тернарный
оператор:
Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8]
new_movie_ratings = [
rating + 0.2 if rating < 4.9 else rating for rating in movie_ratings
]
print(new_movie_ratings)
# Вывод в терминал: [4.9, 5.0, 4.5, 4.0]
Такая запись как пишется — так и читается: «добавь в новый список
rating + 0.2
, если rating < 4.9
, иначе добавь rating
» .Если
задача будет в том, чтобы сформировать список только из значений
рейтинга, которые больше 4.5, тогда нужно использовать только оператор
if
; list comprehension будет выглядеть так:Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8]
new_movie_ratings = [rating for rating in movie_ratings if rating > 4.5]
print(new_movie_ratings)
# Вывод в терминал:[4.7, 5.0]
Распаковка списка
Это удобная операция, благодаря которой возможно одним выражением присвоить значения элементов списка переменным.
Скопировать кодPYTHONweek = [
'Понедельник', 'Втроник', 'Среда',
'Четверг', 'Пятница', 'Суббота', 'Воскресенье'
]
mon, tue, wed, thu, fri, sat, sun = week
print(wed)
# Вывод в терминал: Среда
Но
стоит быть внимательным к числу переменных и распаковываемых элементов:
если их количество будет отличаться — возникнет ошибка:
Скопировать кодPYTHONweek = [
'Понедельник', 'Втроник', 'Среда',
'Четверг', 'Пятница', 'Суббота', 'Воскресенье'
]
mon, tue, wed, thu, fri, sun = week
print(wed)
# Вывод в терминал: ValueError: too many values to unpack (expected 6)
Методы списков
Списки — это изменяемый тип данных, поэтому методы изменяют сам объект списка к которому применены, а не создают новый.
list.append(element) - добавляет элемент в конец списка
Скопировать кодPYTHONmovies = ['Матрица', 'Хакеры', 'Трон']
movies.append('Тихушники')
print(movies)
# Вывод в терминал: ['Матрица', 'Хакеры', 'Трон', 'Тихушники']
Метод
append()
ничего не возвращает, он не создаёт новый объект, а изменяет
существующий. Потому не следует присваивать результат применения метода
переменной: метод ничего не возвращает, и в результате значением такой
переменной окажется None
.Скопировать кодPYTHONmovies = ['Матрица', 'Хакеры', 'Трон']
# Бессмысленно присваивать результат работы метода переменной
new_movies = movies.append('Тихушники')
print(new_movies)
# Вывод в терминал: None
# Метод и не должен был ничего возвращать, он молодец, он выполнил свою работу:
# изменил исходный список.
print(movies)
# Вывод в терминал: ['Матрица', 'Хакеры', 'Трон', 'Тихушники']
list_1.extend(list_2) - расширяет список
list_1
, добавляя в конец все элементы списка list_2
. Визуально результат метода похож на результат конкатенации списков. Разница состоит в том, что - при конкатенации создаётся новый объект, содержащий элементы двух списков;
- метод
extend()
изменяет списокlist_1
.
Скопировать кодPYTHONmovie_ratings = [4.7, 5.0, 4.3, 3.8]
movies = ['Матрица', 'Хакеры', 'Трон']
print(id(movies))
# Вывод в терминал: 2217539360448
movies.extend(movie_ratings)
print(movies)
# Вывод в терминал: ['Матрица', 'Хакеры', 'Трон', 4.7, 5.0, 4.3, 3.8]
print(id(movies))
# Вывод в терминал: 2217539360448
# А при конкатенации в памяти будет создан новый объект, а не изменён существующий:
movies = movies + movie_ratings
print(movies)
# Вывод в терминал: ['Матрица', 'Хакеры', 'Трон', 4.7, 5.0, 4.3, 3.8]
print(id(movies))
# Вывод в терминал: 2217540656384
# Другой ID - другой объект.
При конкатенации создан новый объект, и теперь переменная
movies
ссылается на него.list.insert(index, value)
- подставляет элемент со значением
value
на позициюindex
. - увеличивает индекс элементов, начиная от
index
, на единицу;
Скопировать кодPYTHONmovies = ['Матрица', 'Хакеры', 'Трон']
movies.insert(1, 'Тихушники')
print(movies)
# Вывод в терминал: ['Матрица', 'Тихушники', 'Хакеры', 'Трон']
list.remove(value)
— удаляет первый (при чтении списка слева направо) элемент, значение
которого совпадает с аргументом. Если такого элемента нет в списке —
будет вызвано исключение.
Скопировать кодPYTHONmovies = ['Матрица', 'Тихушники', 'Хакеры', 'Трон']
movies.remove('Хакеры')
print(movies)
# Вывод в терминал: ['Матрица', 'Тихушники', 'Трон']
# Попытка удалить несуществующий объект
# вызовет исключение
movies.remove('Сеть')
# Вывод в терминал: ValueError: list.remove(x): x not in list
list.pop(index) — удаляет из списка элемент с индексом
index
и возвращает его. Если индекс не указан, метод удаляет и возвращает последний элемент списка.Скопировать кодPYTHONmovies = ['Матрица', 'Тихушники', 'Хакеры', 'Трон']
movie = movies.pop(2)
print(movie)
# Вывод в терминал: Хакеры
print(movies)
# Вывод в терминал: ['Матрица', 'Тихушники', 'Трон']
list.index(value, [start [, end]]) — читает список слева направо и возвращает индекс первого найденного элемента со значением
value
. Диапазон поиска можно ограничить индексами start
и end
.Если элемент с заданным значением не найден — будет выведено исключение ValueError.
Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8]
rating = movie_ratings.index(4.3)
print(rating)
# Вывод в терминал: 2
list.count(value) — возвращает количество элементов со значением
value
Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8, 4.7, 4.1]
rating_count = movie_ratings.count(4.7)
print(rating_count)
# Вывод в терминал: 2
list.sort() — сортирует список . У этого метода есть необязательный параметр
reverse
, который определяющий направление сортировки. По умолчанию reverse = False
, элементы сортируются «по возрастанию», от меньшего к большему.Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8, 4.7, 4.1]
movie_ratings.sort()
print(movie_ratings)
# Вывод в терминал: [3.8, 4.1, 4.3, 4.7, 4.7, 5.0]
movies = ['Матрица', 'Хакеры', 'Трон']
movies.sort(reverse = True)
print(movies)
# Вывод в терминал: ['Хакеры', 'Трон', 'Матрица']
list.reverse()
— инвертирует список. Результат работы метода похож на использование
среза [::-1], но, в отличие от среза, этот метод не создаёт новый объект
списка.
Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8, 4.7, 4.1]
print(id(movie_ratings))
# Вывод в терминал: 27337512
# Развоврот списка методом reverse()
movie_ratings.reverse()
print(id(movie_ratings))
# Вывод в терминал: 27337512
print(movie_ratings)
# Вывод в терминал: [4.1, 4.7, 3.8, 4.3, 5.0, 4.7]
Метод
reverse()
изменил исходный список. Если использовать для разворота срез, то результатом будет новый объект.Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8, 4.7, 4.1]
print(id(movie_ratings))
# Вывод в терминал: 2028420139712
# Разворот списка с помощью среза
movie_ratings = movie_ratings[::-1]
print(movie_ratings)
# Вывод в терминал: [4.1, 4.7, 3.8, 4.3, 5.0, 4.7]
# Список инвертирован, но...
print(id(movie_ratings))
# Вывод в терминал: 2028420159168
# Это уже другой объект!
list.copy() — возвращает новый список, независимую копию исходного списка.
Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8, 4.7, 4.1]
copy_movie_ratings = movie_ratings.copy()
print(id(movie_ratings))
# Вывод в терминал: 38282024
print(id(copy_movie_ratings))
# Вывод в терминал: 38281640
# Применим сортировку к исходному списку
movie_ratings.sort()
print(movie_ratings)
# Вывод в терминал: [3.8, 4.1, 4.3, 4.7, 4.7, 5.0]
# Элементы списка-копии остались неотсортированными
print(copy_movie_ratings)
# Вывод в терминал: [4.7, 5.0, 4.3, 3.8, 4.7, 4.1]
Если просто присвоить переменной
copy_movie_ratings
значение movie_ratings
(copy_movie_ratings = movie_ratings
) — копия не создаcтся: обе переменные будут ссылаться на один объект.list.clear() — очищает список, удаляет из него все элементы:
Скопировать кодPYTHONmovie_ratings= [4.7, 5.0, 4.3, 3.8, 4.7, 4.1]
movie_ratings.clear()
print(movie_ratings)
# Вывод в терминал: []
Теперь вы знаете, как управляться со списками. Пора закрепить на практике!
Магистр
Йода состарился и стал совсем плох в речи: он стал менять местами
первое и последнее слово фразы. Напишите программу, которая сможет
привести его фразы в нормальный вид. Не создавая нового объекта,
поменяйте первое и последнее слово местами.
КодPYTHON
12
1
force_words = ['сила', 'пребудет', 'с', 'тобой', 'Да']
2
print(id(force_words))
3
last = force_words.pop()
4
first = force_words.pop(0)
5
force_words.insert(0,last)
6
force_words.append(first)
7
8
9
print(force_words)
10
# Убедимся, что это тот же объект, что и в начале программы
11
print(id(force_words))
12