Алла Тамбовцева, НИУ ВШЭ
range()
¶Как выглядит список, вы уже выяснили, прослушав главу на DataCamp. Список – это структура данных, которая может включать в себя элементы разных типов:
nums = [5, 6, 8, 1]
nums
[5, 6, 8, 1]
names = ["Anna", "Fred", "Tina"]
names
['Anna', 'Fred', 'Tina']
mixed = ["Anna", 10, "Fred", 7]
mixed
['Anna', 10, 'Fred', 7]
.append()
¶Важная особенность списков заключается в том, что они являются изменяемой (mutable) структурой данных. Это означает, что список можно изменять, не переопределяя переменную, в которой этот список сохранен. Чтобы понять, о чём речь, давайте посмотрим сначала на примеры неизменяемых (immutable) объектов в Python. Начнём с целых чисел. Если у нас есть переменная a
, и в ней сохранено целое число, мы сможем изменить её значение только создав новую переменную с таким же названием:
a = 3
a = a + 1 # новое значение
a
4
Другими словами, у нас нет никакого иного способа, который можно было бы применить, чтобы, например, увеличить значение a
, не переопределяя её через оператор =
. То же будет и со строками.
s = "питон греется на солнышке"
Теперь попробуем сделать первую букву заглавной:
s.capitalize()
'Питон греется на солнышке'
Но сама строка пока не изменилась – всё потому, что строка является объектом неизменяемого типа:
s
'питон греется на солнышке'
Чтобы сохранить изменения, нужно переопределить переменную s
:
s = s.capitalize()
s
'Питон греется на солнышке'
К неизменяемым объектам в Python относятся:
Теперь посмотрим на изменяемые объекты. К изменяемым объектам относятся:
Есть список M
:
M = [1, 9, 4]
Заменим первый элемент на 100:
M[0] = 100
M
[100, 9, 4]
Изменения сохранились, но при этом значение переменной M
не пришлось переопределять заново. Теперь припишем в конец списка M
ещё один элемент – для это применим метод .append()
:
M.append(200)
M
[100, 9, 4, 200]
Список M
изменился, но присваивание с =
мы нигде не использовали, мы изменили список «как есть». Более того, если мы исполним что-то такое M = M.append(200)
, мы получим неожиданный результат:
M = M.append(200)
print(M)
None
Результат None
. Почему? Потому что метод .append()
сам по себе не возвращает никакого результата (результат пуст, имеет тип None
), он «молча» записывает элемент в конец списка.
При работе с изменяемыми объектами нужно быть осторожными при создании копии. Если мы работаем с неизменяемыми объектами, можно просто присвоить новой переменной значение старой с помощью =
:
a = 3
b = a
b = b + 1
print(a, b)
3 4
В примере выше мы скопировали значение a
в переменную b
, значение b
изменили, а значение a
изменений не претерпело.
С изменяемыми объектами это бы не сработало. Вернемся к спискам.
L = [1, 6, 7]
L2 = L
L2.append(10)
print(L, L2)
[1, 6, 7, 10] [1, 6, 7, 10]
Несмотря на то, что список L
мы не трогали, он изменился точно так же, как и список L2
! Что произошло? На самом деле, когда мы записали L2 = L
, мы скопировали не сам список, а ссылку на него. Другими словами, проводя аналогию с папкой и ярлыком, вместо того, чтобы создать новую папку L2
с элементами, такими же, как в L
, мы создали ярлык L2
, который сам по себе ничего не содержит, а просто ссылается на папку L
.
Так как же тогда копировать списки? Во-первых, у списков есть метод .copy()
.
L = [1, 6, 7]
L2 = L.copy()
L2.append(10)
print(L, L2)
[1, 6, 7] [1, 6, 7, 10]
Во-вторых, можно сделать полный срез срез и «срезать» весь список:
L = [1, 6, 7]
L2 = L[:]
L2.append(10)
print(L, L2)
[1, 6, 7] [1, 6, 7, 10]
.extend()
vs метод .append()
¶Метод .append()
используется, если в конец списка нужно приписать один элемент. А что, если нужно добавить сразу несколько элементов? Метод .append()
уже не подойдёт:
a = [7, 2, 1, 8]
a.append(3, 4)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-17-20f19072f5fc> in <module> 1 a = [7, 2, 1, 8] ----> 2 a.append(3, 4) TypeError: append() takes exactly one argument (2 given)
А если объединить элементы в список, метод .append()
сработает, но результат будет отличаться от ожидаемого:
a.append([3, 4]) # список [3, 4] как отдельный элемент
a
[7, 2, 1, 8, [3, 4]]
Поэтому в таком случае нужно использовать особый метод, метод .extend()
:
a = [7, 2, 1, 8]
a.extend([3, 4])
a
[7, 2, 1, 8, 3, 4]
Результат выше совпадает с тем, что мы бы получили, «склеивая» два списка через +
:
a = [7, 2, 1, 8]
a + [3, 4]
[7, 2, 1, 8, 3, 4]
range()
¶В Python есть функция range()
, которая позволяет перебирать целые числа на заданном промежутке, не создавая при этом сам список чисел.
# пример
for j in range(0, 6):
print(j)
0 1 2 3 4 5
Правый конец заданного в range()
промежутка не включается, будьте бдительны. В примере выше на экран были выведены числа от 0 до 5, число 6 включено не было.
Если мы хотим посмотреть на то, какие значения будут в range()
, придется превратить его в список:
range(0, 3) # не поспоришь, но бесполезно
range(0, 3)
list(range(0, 3)) # значения внутри range
[0, 1, 2]
Полезный факт: если нас интересуют числа на промежутке, начиная с нуля, в range()
левый конец можно не указывать, 0 будет выбран по умолчанию.
list(range(5))
[0, 1, 2, 3, 4]
Еще один полезный факт: шаг (разность между последующими элементами) для последовательности целых чисел можно выставить самостоятельно. Для этого достаточно дописать третье число – значение шага – внутри функции range()
:
list(range(0, 18, 2)) # шаг 2
[0, 2, 4, 6, 8, 10, 12, 14, 16]
list(range(0, 18, 3)) # шаг 3
[0, 3, 6, 9, 12, 15]