Лекция 3. Списки

Основным составным типом данных в языке Python3 является список (тип данных list). Несмотря на то, что название этого типа похоже на названия связных списков в языке C, списки в питоне аналогичны массивам языка C и так же предоставляют постоянное время доступа по индексу, не зависящее от значения индекса.

Списки в исходном коде на Python обозначаются так:

L = []  # Пустой список
L = [10, 20]  # Список из двух чисел
L = [1, 'A' ,10]  # Благодаря динамической типизации, в списке могут хранится
                  # элементы различных типов
L = [[10, 20], [30, 40]]  # Список со вложенными списками, аналог двумерного
                          # массива в C.
L = list('abc')        # аналогично ['a', 'b', 'c']
L = list(range(0, 9))  # аналогично [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Индексы

Чтение и запись по индексу происходит стандартным образом:

L = [10, 20, 30, 40]

print(len(L))  # len -- функция, возвращающая длину списка,
               # здесь её результат равен 4

x = L[0]     # Чтение по индексу, элементы нумеруются от нуля
print(L[1])

L[0] = 100   # Запись по индексу
L[2] = 300
L[-1] = 400  # Отрицательные индексы отсчитываются от конца списка.
L[-2] = 200

print(L)     # print выводит весь список целиком, в данном случае
             # на вывод будет отправлена строка "[100, 200, 300, 400]\n"

Обход списка в цикле for

Чтобы пройтись по списку, можно просто подставить его в цикл for:

L = [10, 20, 30]

for i in L:
    # тело цикла будет выполняться сначала для L[0],
    # затем для L[1] и так далее.
    print(i)

# Этот цикл выведет:
#   10
#   20
#   30

Такая форма записи крайне удобна, так как позволяет избавится от постоянной записи индекса после имени массива, но зато не позволяет изменять значения ячеек списка. То есть, присвоение переменной i изменит только переменную i, а элемент списка останется без изменений.

Чтобы была возможность изменять список, нужно воспользоваться записью с перебором индексов списка:

L = [10, 20, 30]

for i in range(len(L)):
    L[i] = L[i] * L[i]

# Теперь в списке L лежат числа 100, 400, 900.

Синтаксис вызова методов

Кроме функций, многими из которых мы уже пользовалась, в Python есть методы, которые во многом похожи на функции, но имеют несколько отличный от функций синтаксис вызова.

Вызываются методы следующим образом:

объект.имяметода(аргумент1, аргумент2, ...)

Или же, если необходимо сохранить возвращаемое значение, таким:

переменная = объект.имяметода(аргумент1, аргумент2, ...)

Внешне всё выглядит таким образом, как будто у нас есть функция, один из аргументов которой записан перед ней через точку. Методы могут использовать как аргументы, записанные в скобках, так и объект, записанный перед ними. Например, метод append добавит элемент в конец списка, для которого он вызван:

L.append(123)   # Изменит содержание списка L.

Зачем нам понадобились методы, когда уже есть функции, мы разберёмся с вами, когда будем проходить объектно-ориентированное программирование.

Методы списков: добавление элементов в список

Двумя самыми основными и часто используемыми методами списков являются append и pop. append добавляет новый элемент в конец списка, pop удаляет элемент из списка и возвращает этот элемент.

L = []  # пустой список
L.append(10)  # В списке [10]
L.append(20)  # В списке [10, 20]

Для добавления элемента в середину или начало списка предназначен метод insert, который принимает индекс и значение для вставки. После вставки новый элемент будет иметь указанный индекс.

L = [10, 20, 30]
L.insert(1, 'abc')
# теперь в L список [10, 'abc', 20, 30]

Методы списков: удаление элементов

Метод pop без аргументов удаляет последний аргумент и возвращает его:

L = [10, 20, 30]
x = L.pop()
# Теперь в L список [10, 20]
# а в x число 30

Если же передать pop индекс элемента, то он удалит и вернёт элемент с таким индексом:

L = [10, 20, 30, 40, 50]
x = L.pop(1)
# Теперь в L список [10, 30, 40, 50]
# а в x число 20

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

L = [10, 20, 30, 40, 50]
x = L.remove(30)
# Теперь в L список [10, 20, 40, 50]

Чтобы удалить все элементы из списка, можно воспользоваться следующими двумя строками:

while x in L:
    L.remove(x)

К сожалению, это не самый быстрый способ, так как и метод remove, и оператор in будут искать элемент каждый раз с начала. Более быстрый вариант мы рассмотрим в теме про генераторы списков.

Поиск значений в списке

Проверить наличие элемента в списке можно с помощью оператора in:

20 in [10, 20, 30]    # True
500 in [10, 20, 30]   # False

Найти индекс элемента можно с помощью метода index. Если данного элемента нет в списке, то метод выдаст ошибку.

L = [10, 20, 30, 40]
print(L.index(30))   # выведет 2

Метод sort

Метод sort сортирует список в возрастающем порядке

L = [12.3, 10, 1, 20, 5]
L.sort()
# теперь в L список [1, 5, 10, 12.3, 20]

L = ['TT', 'TX', 'def', 'ZAA', 'ZA', 'abc', 'aba', '^_^', ':)']
L.sort()
# теперь в L список [':)', 'TT', 'TX', 'ZA', 'ZAA', '^_^', 'aba', 'abc', 'def']

Как видно, sort сортирует элементы в соответствии с операцией сравнения >. При этом строки сортируются “по алфавиту”, если считать алфавитом порядок символов в кодовой таблице.

Если значения элементов не сравнимы с помощью операции >, то метод sort выдаст ошибку.

Прочие методы

Метод clear полностью очищает список.

L = [10, 20]
L.clear()
# теперь в L пустой список []

Метод reverse переставляет элементы списка в обратном порядке. Он ничего не возвращает (то есть, возвращает специальный объект None, который означает отсутствие у функции возвращаемого значения), а все изменения в порядке элементов сохраняются в том списке, к которому он был применён.

L = ['ab', 'cd', 'xyz']
L.reverse()
print(L)      # ['xyz, 'cd', 'ab']

Метод extend добавит список значений в конец списка:

L = [10, 20, 30]
L1 = [40, 50]
L.extend(L1)
print(L)      # список [10, 20, 30, 40, 50]

Метод count считает число вхождений объекта в список:

L = [10, 20, 10, 10]
c = L.count(10)       # В переменную c сохранится число 3.

Распаковка списков

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

a, b = b, a

Такой же синтаксис можно использовать и для распаковки списков в переменные:

L1 = [10, 20]
a, b = L1       # аналогично a, b = L[0], L[1]

L2 = [10, 20, 30]
a, b, c = L2    # аналогично a, b, c = L[0], L[1], L[2]

Если количество переменных слева от присваивания не соответствует числу элементов в списке справа, интерпретатор Python выдаст ошибку. Однако, если известно, что список содержит, например, не менее двух элементов, можно указать для “лишних” отдельную переменную:

L = [10, 20, 30, 40, 50]
a, b, *c = L # В переменных a и b первые элементы, в переменной c остальные
print(a, b, c)  # 10 20 [30, 40, 50]

L = [10, 20, 30, 40, 50]
a, *b, c = L # В a первое значение, в c последнее, в b остальные
print(a, b, c)  # 10 [20, 30, 40] 50

L = [10, 20]
a, b, *c = L  # для переменной c не хватает элементов,
              # в ней будет пустой список
print(a, b, c)  # 10 20 []

Слева от присваивания может стоять только одна переменная, помеченная оператором *.

Функции sum, min, max

При работе со списками чисел крайне полезны встроенные функции sum, min, max, вычисляющие, соответственно, сумму элементов, минимум и максимум.

L = [10, 20, 30]
print(sum(L), min(L), max(L))  # 60 10 30

Функция sum на пустом списке возвращает ноль. Функции min и max на пустом списке вызывают ошибку.

Как видно из примера выше, если функциям min или max передать один аргумент, то они ищут минимум или максимум среди его элементов. Если же этим функциям передать не один аргумент, а несколько, они будут вычислять минимум и максимум среди этих аргументов:

a = min(10, 1)        # 1
b = max(10, 100, 1)   # 100