list - списки

Список - это упорядоченная, изменяемая последовательность любых объектов языка Python.

Создание с помощью литералов []

Простейший способ создать список - перечислить его элементы через запятую и заключить их в квадратные скобки:

>>> l = [1, 2, 3, 'a', 'b', 'c']
>>> l
[1, 2, 3, 'a', 'b', 'c']

Если указать только квадратные скобки, то будет создан пустой список:

>>> l = []
>>> l
[]

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

>>> m = [[1, 2, 3],
...      [2, 2, 3],
...      [3, 3, 3]]
>>> m
[[1, 2, 3], [2, 2, 3], [3, 3, 3]]

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

>>> data = [['Bob', 'm', 25, 'manager', 2300],
...         ['Lisa', 'f', 26, 'designer',2800],
...         ['Grag', 'm', 31, 'engineer', 3100],
...         ['Sara', 'f', 29, 'engineer', 3100]]

Создание с помощью генераторов списков

В некоторых случаях, когда необходимо создать очень большой список с элементами которые получаются с помощью простого правила, то гораздо удобнее создавать его не вручную, а с помощью генераторов списков:

>>> [n**2 for n in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Генераторы списков, довольно просты в использовании, к ним нужно просто привыкнуть. По сути, генераторы это просто вывернутые наизнанку циклы for и они вовсе не обязаны быть одномерными, т.е. генераторы вложенные друг в друга позволяют создавать списки вложенные в другие списки:

>>> [[x for x in range(y, y + 10)] for y in range(10)]
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
 [2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
 [3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
 [4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
 [5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
 [6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
 [7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
 [8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
 [9, 10, 11, 12, 13, 14, 15, 16, 17, 18]]

Функция list()

Еще один способ создания списков заключается в том чтобы использовать встроенную функцию list(). Если вызвать данную функцию без аргументов, то будет возвращен пустой список:

>>> list()
[]

Если передать функции list любой итерируемый объект, то он так же будет преобразован в список, например, вот так список может быть получен из строки:

>>> list('abcdefg')
['a', 'b', 'c', 'd', 'e', 'f', 'g']

Помимо строк, аргументом может быть любой итератор, например range():

>>> list(range(5, 160, 10))
[5, 15, 25, 35, 45, 55, 65, 75, 85, 95, 105, 115, 125, 135, 145, 155]

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

>>> x = (1, 2, 3, 4, 5)    # кортеж
>>> list(x)
[1, 2, 3, 4, 5]

Словарь, который хранит данные в виде пар ключ - значение, так же может быть преобразован в список, но в результирующий список попадут только имена ключей:

>>> x = {'a': 1, 'b': 2, 'c': 3}     # словарь
>>> list(x)
['a', 'b', 'c']

Множества, которые хранят только уникальные объекты, так же могут быть преобразованы в списки:

>>> x = {1, 'c', 4, 'b', 'd', 4, 2}    # множество
>>> list(x)
[1, 2, 'b', 4, 'd', 'c']

Даже строки байтов могут быть преобразованы в список:

>>> x = b'\x61\x31\x62\x32\x63\x33' # строка байтов
>>> list(x)
[97, 49, 98, 50, 99, 51]

Ну а если функции list() передать список, то он будет возвращен как бы без изменений, но на самом деле будет возвращена его поверхностная копия:

>>> x = [1, 2, 3, 4, 5]
>>> list(x)
[1, 2, 3, 4, 5]

Спискок - это последовательность

Выше было сказано, что если в качестве аргумента функции list() передать любую последовательность языка Python, то она будет преобразована в список. Последовательностями считаются любые типы данных, которые поддерживают:

  • оператор извлечения срезов - [START:STOP:STEP];
  • оператор вхождения in;
  • возможность определения длины (размера) с помощью функции len();
  • возможность выполнять итерации по элементам;

Списки считаются последовательностями поскольку удовлетворяют всем вышеперечисленным требованиям. Функция len() возвращает длину (размер) списка:

>>> x = [1, 'a', 2, 'b', 3, 'c', 4, 'd']
>>>
>>> # определение длины списка:
>>> len(x)
8

Но будьте внимательны, len() не учитывает длину вложенных элементов, например, список [1, 'abc', [55, 66, 77]] состоит из трех элементов: числа, строки и списка.

Извлекать данные можно с помощью оператора [START:STOP:STEP]:

>>> x[0]     # индекс первого элемента равен 0
1
>>>
>>> x[1:6]     # срез элементов с 1 до 6
['a', 2, 'b', 3, 'c']
>>>
>>> x[::-2]    # элементы взятые в обратном порядке с шагом 2
['d', 'c', 'b', 'a']

Проверить вхождение какого-нибудь элемента в список можно с помощью оператора in:

>>> x = list('1a2b3c4d')
>>> x
['1', 'a', '2', 'b', '3', 'c', '4', 'd']
>>>
>>> 'a' in x
True
>>>
>>> 'e' in x
False

Кстати, если вам нужно, наоборот, убедиться в том, что какой-нибудь элемент не содержится внутри списка, то можно воспользоваться конструкцией not in:

>>> 'e' not in x
True
>>>
>>> 'a' not in x
False

Возможность выполнения итераций по элементам так же возможна благодаря конструкции for... in...

>>> for n in x:
...     print(n*10)
...
1111111111
aaaaaaaaaa
2222222222
bbbbbbbbbb
3333333333
cccccccccc
4444444444
dddddddddd

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

>>> for x, y in [[1, 2], [3, 4], [5, 6], [7, 8]]:
...     print(x, '+', y, '=', x+y)
...
1 + 2 = 3
3 + 4 = 7
5 + 6 = 11
7 + 8 = 15

Список - это упорядоченная последовательность

Список является упорядоченной последовательностью в том смысле, что все его объекты упорядочены по своему местоположению, а доступ к ним выполняется с помощью целочисленных индексов, которые и определяют местоположение элементов.

Выше мы уже видели, что механизм индексации списков аналогичен индексации строк с помощью оператора [START:STOP:STEP]. Но из-за того, что список может содержать внутри себя абсолютно любые объекты, включая другие последовательности, то возникает необходимость в более сложных методах индексации:

>>> lst = [7, 'abc', [['A', 'B'], ['C', 'D']]]
>>>
>>> lst
[7, 'abc', [['A', 'B'], ['C', 'D']]]

Например, если необходимо получить доступ к символу 'D', то его местоположение придется указывать с помощью трех операторов []:

>>> lst[2][1][1]
'D'

Несмотря на количество вложенных списков, получить доступ можно к абсолютно любому элементу, хотя с непривычки все-таки можно "заблудиться в трех соснах".


Списки - это изменяемые последовательности

Элементы списков и даже целые фрагменты списков могут быть изменены:

>>> x = list('abcdefg')
>>> x
['a', 'b', 'c', 'd', 'e', 'f', 'g']

Чтобы изменить какой-нибудь элемент, достаточно обратиться к нему по индексу и указать его новое значение после оператора присваивания =:

>>> x[0] = 111
>>> x
[111, 'b', 'c', 'd', 'e', 'f', 'g']

Вставить элемент в определенную позицию можно следующим способом:

>>> x[2:2] = [222]
>>> x
[111, 'b', 222, 'c', 'd', 'e', 'f', 'g']

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

>>> x[-3:-1] = [333, 444]
>>> x
[111, 'b', 222, 'c', 'd', 333, 444, 'g']

Если присвоить срезу списка пустой список, то это приведет к удалению элементов, которые входят в указанный срез:

>>> x[3:5] = []
>>> x
[111, 'b', 222, 777, 'g']

Списки - это коллекции

Списки очень часто называют коллекциями, как раз потому что в отличие от массивов они могут содержать объекты разного типа и произвольные структуры данных (словари, множества и т.д.):

>>> x = [1, .01, 1 + 1j, 'abc', [.01, .02, .03]]
>>> x
[1, 0.01, (1+1j), 'abc', [0.01, 0.02, 0.03]]

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

>>> [1, 2, 3, 4, 5]    # массив целых чисел
[1, 2, 3, 4, 5]
>>> [.1, .2, .3, .4]   # массив вещественных чисел
[0.1, 0.2, 0.3, 0.4]
>>> ['a', 'b', 'c']    # массив символов Юникода
['a', 'b', 'c']

Пожалуй, единственное, где стоит относиться к спискам как к массивам, т.е. стараться что бы все элементы были одинакового типа - это научные вычисления и обработка данных с помощью таких пакетов как NumPy и Pandas. В этих случаях типизация массивов позволяет существенно ускорить работу алгоритмов. А во всех остальных случаях, списки - это самые настоящие коллекции, в которых можно хранить все что угодно, лишь бы это "что угодно" было объектом языка Python. Например, функции являются объектами языка Python, а значит они тоже могут храниться в списках, скажем вот так:

>>> F = [int, str, list, sum, dir]
>>> F
[<class 'int'>, <class 'str'>, <class 'list'>, <built-in function sum>, <built-in function dir>]

Более того, эти функции можно использовать, если вызвать их из списка с помощью оператора []. Например, функция int() преобразует (если это возможно) любой объект в целое десятичное число:

>>> int(0b1001001)    # преобразуем двоичное число в десятичное
73

А вот мы делаем тоже самое с помощью функции, которая хранится в списке F:

>>> F[0](0b1001001)
73

Вот так мы преобразуем число в строку:

>>> F[1](1000)
'1000'

А вот так мы можем сначала сделать из числа строку а потом из этой строки сделать список:

>>> F[2](F[1](1234))
['1', '2', '3', '4']

Вот таким образом может быть найдена сумма элементов списка:

>>> F[3]([1, 2, 3, 4])
10

А если хочется взглянуть на функции и методы, которые поддерживают списки, то можем выполнить F[4](F).

Такие примеры могут только запутать, но данный пример показывает что любой объект языка Python может быть элементом в списке (и в любой другой коллекции), а значит он может быть использован и даже передан в другие списки.