Коллекции. Списки и кортежи
Полезная информация о print
Функция print()
имеет необычные аргументы. В консоль можно выводить сразу несколько аргументов, разделяя их запятой. Аргументы могут быть разных типов данных.
Обратите внимание, что между строкой и числом ставится пробел, который ставится по умолчанию. Если после всех аргументов для вывода в консоль написать аргумент с именем sep
, то вместо пробела, будет другой разделяющий символ. Например, набор символов \n
, который позволяет сделать перенос строки на следующую.
Именованный аргумент end
убирает символ переноса строки по умолчанию и ставит то, что указано в функции.
Разновидности коллекций
Мы разобрали несколько типов данных (int
, float
и str
), которые позволяют нам представить данные в виде абстракции. Но что если, нам нужно обратиться к совокупности подобных абстракций.
Для этого в Python выделяют коллекции
- объекты-контейнеры, которые хранят другие объекты, чтобы обращаться к ним как к единой абстрации. Это позволяет также применять специальные функции и методы.
В Python существуют следующие коллекции.
- Списки
list
- Кортежи
tuple
- Множества
set
- Словари
dict
Списки
Рассмотрим списки list
– изменяемые коллекции, которые можно формировать из любых объектов, а также добавлять в список и удалять из него элементы.
Примеры создания списков в блоке кода ниже.
shop_lst = ['apple', 'banana', 'orange'] # список строк
primes = [1, 2, 3, 10, 15, -20] # список чисел
# пустой список
empty_lst = []
# или
empty_lst = list()
# список может состоять из списков и переменных
lst = [[1, 2, 3], [4, 5, 6], digits]
# то есть, список может включать что угодно!
lst = [1, ["a", True], "b"]
Обратите внимание на имя переменной lst
. Так можно указать, что за переменной скрывается список, но не использовать при этом символ i
, который часто можно встретить как имя переменной цикла
Список, как и строки, можно индексировать поэлементно.
shop_lst = ['apple', 'banana', 'orange']
# индексация списков
print(shop_lst[0])
print(shop_lst[::-1])
Методы
Некоторые типы данных обладают специфическими свойствами. Например, строку str
, которая содержит символы abc, можно отобразить в верхнем регистре, как ABC, а число int
нельзя перевести в верхний регистр.
Метод
– это функция, которая задана для конкретного типа данных (функция, которая определена внутри класса). Методы также принимают параметры и выполняют определенный код, но они всегда привязаны к конкретному типу данных. Поэтому нельзя вызвать метод, которого у соответствующего типа данных нет.
Использование методов можно увидеть в Задаче №1. Для исследуемой строки был использованы методы find
rfind
и split
. Методы также существуют и для списков. Ниже приведены некоторые из них.
Название | Обозначение |
---|---|
append(x) |
добавить элемент в конец списка |
insert(i, x) |
вставить элемент перед указанным индексом |
pop(i) |
вытащить элемент из списка по индексу и убрать его из списка |
Пример использования метода списка append
.
lst = [1, 2, 3] # список чисел
lst.append(4) # метод добавления числа в конец списка
100.append(4) # Ошибка! Такого метода для int не существует
Кортежи. Отличия от списков
Кроме списков часто можно встретить кортежи tuple
- неизменяемые коллекции. Кортеж можно создать следующим образом.
rainbow = ("red", "green", "blue") # кортеж строк
empty_tpl = () # пустой кортеж
# или
empty_tpl = tuple()
Для чего нужен кортеж?
- Он создается быстрее списка. Следует помнить, что коллекция занимает в памяти компьютера зарезервированное место, а по соседству с ней могут находиться ячейки, занятые другими объектами. Кроме того, каждый элемент коллекции нужно пронумеровать и в случае, если коллекция имеет возможность хранить новые элементы, то все индексы предыдущих элементов будут сдвигаться. Такой коллекцией является список и для его создания и изменения требуется много времени, в отличии от работы с кортежем.
Проверить данное утверждение можно следующем образом. Чтобы вывести в консоль информацию о существующих методах для типа данных, можно использовать функцию dir()
.
Вывод будет выглядеть следующим образом.
Мы получили список доступных методов для типа данных tuple
. Обратите внимание, что методы, которые начинаются с двойного подчеркивания, мы не рассматриваем. Это магические методы Python, о которых подробнее можно узнать в объектно-ориентированном программировании на Python. После них начинаются имена методов без нижнего подчеркивания, которые нам и нужны. Из доступных для кортежа методов есть только два: count
и index
.
Теперь рассмотрим доступные методы для списка.
Для списков вывод будет выглядеть следующим образом.
[ ... , '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
Для списков доступно 11 методов! В списки можно добавлять значения, удалять их, менять порядок элементов и тд. Для кортежей можно посчитать количество идентичных элементов и найти индекс элемента (методы count
и index
, соответственно). Поэтому списки list
являются изменяемыми коллекциями, а кортежи tuple
неизменяемыми.
Для чего еще нужен кортеж?
-
В Python многие операции работают за счет кортежей. Например, множественное присвоение. Также некоторые функции возвращают пары значений, которые сформированы в кортежи, как показано в примере b. Об этом мы поговорим в следующих разделах.
a. множественное присвоение
b. возвращаемые значения
Проблема изменяемых коллекций
В чем разница между изменяемыми и неизменяемым коллекциями? Например, между list
и tuple
.
Рассмотрим следующий пример. Создадим список городов towns. Иногда можно возникнуть необходимость дублировать объект, чтобы не менять исходник. Поэтому мы попробуем создадим копию через создании переменной cities и добавим к копии списка новый город.
Обратите внимание! Для чисел или строк описанный выше способ сработает!
Тем не менее, для списка ответ будет несколько иным.
# список городов
towns = ["Москва", "Санкт-Петербург", "Казань"]
# Дублируем его в другую переменную
cities = towns
cities.append("Новосибирск")
# посмотрим на cities и towns
print("cities -", cities)
print("towns -", towns)
То есть, изменив что-то в одном списке, изменения происходят и в исходном!
Для кортежа ситуация будет такой же, как и чисел
rainbow = ("red", "green", "blue")
# Выше мы объявили кортеж цветов rainbow
# дублируем его в другую переменную
colors = rainbow
colors += ("violet",)
# посмотрим на colors и rainbow
print("colors -", colors)
print("rainbow -", rainbow)
Конечно, методы вызываемые для списка меняют сам список, вне зависимости от количества имен переменных, которые к нему привязаны. Вы можете провести сложение списков и увидите, что они действительно изменятся. Однако, учитывайте, что методы списка list
меняют сам список и для всех переменных, которые к нему привязаны, тоже произойдут изменения. Для кортежей будет происходить создание нового кортежа tuple
с новым набором элементов. Поэтому кортежи являются неизменяемыми.
Ниже приведен список изменяемых и неизменяемых типов данных в Python.
Неизменяемые | Изменяемые |
---|---|
числа int |
списки list |
вещественные числа float |
словари dict |
кортежи tuple |
множества set |
строки str |
|
логический тип данных bool |
Множества
Немного о множествах. Множество set
– это изменяемая коллекция уникальных неупорядоченных элементов.
Множество можно создать с помощью set()
. Также существует запись с помощью фигурных скобок при наличии более одного элемента.
В множество каждый элемент может входить только один раз! Например, если записать в множестве строку, то получим множество символов, которые не повторяются.
Как и в математике, множества в Python имеют те же свойства: объединение, пересечение и другие операции о которых подоробнее вы можете узнать по ссылке.
Промежуточный итог и справка по вопросам
Теперь вы знаете что такое списки и кортежи, какие для них встречаются методы. Следующие параграфы посвящены вопросам по теме. Постарайтесь ответить на предложенные вопросы сначала самостоятельно, потом перейти к объяснениям. В объяснениях будет рассмотрен подробнее новый материал, поэтому обязательно изучите их.
Вопросы по теме
Вопрос 1
Каким будет результат выполнения кода ниже?
a = [10, 20]
b = a
b += [30, 40]
print(a)
print(b)
# [10, 20], [10, 20, 30, 40]
# [10, 20, 30, 40], [10, 20, 30, 40]
Вопрос 2
Каким будет результат выполнения кода ниже?
a = ['раз', 'два', 'три']
print('четыре'.join(a))
# ['раз', 'два', 'три', 'четыре']
# ['раз два три четыре']
# 'раз два три четыре'
# 'разчетыредвачетыретри'
Вопрос 3
Каким будет результат выполнения кода ниже?
Вопрос 4
Каким будет результат выполнения кода ниже?
lst = [13, 56, 17]
lst.append([87])
lst.extend([45, 67])
print(lst)
# [13, 56, 17, 87, 45, 67]
# [13, 56, 17, [87], 45, 67]
# [13, 56, 17, [87], [45, 67]]
# [13, 56, 17, 87, [45, 67]]
Вопрос 5
Каким будет результат выполнения кода ниже?
strLst = list("Python")
strLst.sort()
str_ = " ".join(strLst)
print(str_)
# ['h', 'n', 'o', 'P', 't', 'y']
# h n o P t y
# ['P', 'h', 'n', 'o', 't', 'y']
# P h n o t y
Вопрос 6
Каким будет результат выполнения кода ниже?
Вопрос 7
Каким будет результат выполнения кода ниже?
Вопрос 8
Каким будет результат выполнения кода ниже?
grif = ['Гарри', 'Гермиона', 'Рон', 'Невилл']
slis = grif.index('Драко')
print(slis * 3)
# Драко Драко Драко
# Гарри
# Гарри Гарри Гарри
# ['', '', '']
# Error
Вопрос 9
Каким будет результат выполнения кода ниже?
lstOne = list('bob')
lstTwo = list('obo')
lstThree = list('bo')
print(lstOne + lstTwo - 2 * lstThree)
# ['bob', 'o']
# ['b', 'o', 'bob', 'o']
# []
# Error
Вопрос 10
Каким будет результат выполнения кода ниже?
Вопрос 11
Каким будет результат выполнения кода ниже?
lst = [2, 4, 6, 8]
lst = lst + (10, )
print(lst)
# [12, 4, 6, 8]
# [12, 14, 16, 18]
# [2, 4, 6, 8, 10]
# TypeError
Вопрос 12
Каким будет результат выполнения кода ниже?
tup = (1, 'Python', 'P')
var = tup[1:2]
print(type(var))
# <class 'string'>
# <class 'tuple'>
# <class 'list'>
# Error
Ответы на вопросы и пояснения
Ответ на вопрос 1
Каким будет результат выполнения кода ниже?
a = [10, 20]
b = a
b += [30, 40]
print(a)
print(b)
# [10, 20], [10, 20, 30, 40]
# [10, 20, 30, 40], [10, 20, 30, 40] <- правильно
Обратите внимание!
Т.к. b и а отсылаются к одному объекту, использование += на b меняет значение и a, и b.
Ответ на вопрос 2
Каким будет результат выполнения кода ниже?
a = ['раз', 'два', 'три']
print('четыре'.join(a))
# ['раз', 'два', 'три', 'четыре']
# ['раз два три четыре']
# 'раз два три четыре'
# 'разчетыредвачетыретри' <- правильно
Обратите внимание!
Метод .join
объединяет список строк в одну большую строку. В данном случае 'четыре' выступает как строка-соединитель.
Ответ на вопрос 3
Каким будет результат выполнения кода ниже?
lst = [1, 2, 3]
lst_cpy = lst.copy()
print(lst_cpy is lst)
# True
# False <- правильно
# None
# Error
Обратите внимание!
Так как lst_cpy
и lst
отсылаются к разным объектам, сравнение через is
выдаст False
. Подробнее про оператор is
по ссылке.
Ответ на вопрос 4
Каким будет результат выполнения кода ниже?
lst = [13, 56, 17]
lst.append([87])
lst.extend([45, 67])
print(lst)
# [13, 56, 17, 87, 45, 67]
# [13, 56, 17, [87], 45, 67] <- правильно
# [13, 56, 17, [87], [45, 67]]
# [13, 56, 17, 87, [45, 67]]
Обратите внимание!
Функция .append()
просто добавляет аргументы в конец списка «как есть», в то время как .extend()
сначала расширяет список, а затем дополняет его аргументами.
Ответ на вопрос 5
Каким будет результат выполнения кода ниже?
strLst = list("Python")
strLst.sort()
str_ = " ".join(strLst)
print(str_)
# ['h', 'n', 'o', 'P', 't', 'y']
# h n o P t y
# ['P', 'h', 'n', 'o', 't', 'y']
# P h n o t y <- правильно
Обратите внимание!
Сначала мы создаём список strLst = ['P', 'y', 't', 'h', 'o', 'n']
, который тут же сортируем. В итоге получаем ['P', 'h', 'n', 'o', 't', 'y']
Затем этот список мы превращаем в строку, где каждый элемент strLst
будет разделён при помощи пробела. Итоговый вариант (P h n o t y)
и выводим на экран
Ответ на вопрос 6
Каким будет результат выполнения кода ниже?
Обратите внимание! При умножении списка на 0 или отрицательное число, мы получаем пустой список.
Ответ на вопрос 7
Каким будет результат выполнения кода ниже?
lst = [0, 2, 3, 4]
lst.pop(1)
print(lst)
# [0, 1, 2, 3, 4]
# [0, 2, 3, 4, 1]
# [0, 3, 4] <- правильно
# Error
Обратите внимание!
Функция pop(n)
убирает элемент с индексом n из списка. В данном случае pop(1)
удаляет элемент 2, оставляя лишь [0, 3, 4]
Ответ на вопрос 8
Каким будет результат выполнения кода ниже?
grif = ['Гарри', 'Гермиона', 'Рон', 'Невилл']
slis = grif.index('Драко')
print(slis * 3)
# Драко Драко Драко
# Гарри
# Гарри Гарри Гарри
# ['', '', '']
# Error <- правильно
Обратите внимание!
Задача index()
— найти позицию, на которой находится аргумент в заданном списке
Так как элемента 'Драко' в списке grif
не существует, то и выводится ошибка
Ответ на вопрос 9
Каким будет результат выполнения кода ниже?
lstOne = list('bob')
lstTwo = list('obo')
lstThree = list('bo')
print(lstOne + lstTwo - 2 * lstThree)
# ['bob', 'o']
# ['b', 'o', 'bob', 'o']
# []
# Error <- правильно
Обратите внимание!
У типа данных list
нет операции вычитания. Отсюда и ошибка: TypeError: unsupported operand type(s) for -: 'list' and 'list'
Ответ на вопрос 10
Каким будет результат выполнения кода ниже?
fvar = 0,3
ivar = 3
print(fvar * ivar)
# 0,9
# [0, 3], [0, 3], [0, 3]
# (0, 3, 0, 3, 0, 3) <- правильно
# Error
Обратите внимание!
fvar = 0,3
создаёт переменную, в которой хранится tuple
вида (0, 3). В итоге умножая это дело на ivar
, равный 3, мы получаем итоговый ответ — (0, 3, 0, 3, 0, 3)
Ответ на вопрос 11
Каким будет результат выполнения кода ниже?
lst = [2, 4, 6, 8]
lst = lst + (10, )
print(lst)
# [12, 4, 6, 8]
# [12, 14, 16, 18]
# [2, 4, 6, 8, 10]
# TypeError <- правильно
Обратите внимание!
TypeError — операция конкатенирования («склеивания») возможна лишь между списком list
и списком. В данном случае (10, ) — это tuple
.
Ответ на вопрос 12
Каким будет результат выполнения кода ниже?
tup = (1, 'Python', 'P')
var = tup[1:2]
print(type(var))
# <class 'string'>
# <class 'tuple'> <- правильно
# <class 'list'>
# Error
Обратите внимание!
Элемент tup[1:2]
всё ещё является частью типа данных tuple
. Если вывести print(var)
, то консоль выведет ('Python', )
.