Списки и кортежи являются самыми универсальными и полезными типами данных в Python. Вы найдете их практически в каждой нетривиальной программе Python.
Содержание
Что вы узнаете из этого урока: Вы узнаете о важных характеристиках списков и кортежей. Вы научитесь определять их и манипулировать ими. После прохождения урока у вас должно быть хорошее представление о том, когда и как использовать эти типы объектов в программе Python.
Списки Python
Список - это набор произвольных объектов, несколько схожий с массивом во многих других языках программирования, но более гибкий. Списки определяются в Python путем заключения разделенной запятыми последовательности объектов в квадратные скобки ([]), как показано ниже:
>>> a = ['foo', 'bar', 'baz', 'qux'] >>> print(a) ['foo', 'bar', 'baz', 'qux'] >>> a ['foo', 'bar', 'baz', 'qux']
Важными характеристиками списков Python являются следующие:
- Списки упорядочены.
- Списки могут содержать любые произвольные объекты.
- Элементы списка могут быть доступны по индексу.
- Списки могут быть вложены на произвольную глубину.
- Списки изменчивы.
- Списки являются динамическими.
Каждая из этих особенностей рассматривается более подробно ниже.
Упорядоченные списки
Список - это не просто набор объектов. Это упорядоченная коллекция объектов. Порядок, в котором задаются элементы при определении списка, является врожденной характеристикой этого списка и сохраняется в течение всего срока его существования. (Вы увидите тип данных Python, который не упорядочен в следующем учебнике по словарям.)
Списки, содержащие одни и те же элементы в другом порядке, не являются одинаковыми:
>>> a = ['foo', 'bar', 'baz', 'qux'] >>> b = ['baz', 'qux', 'bar', 'foo'] >>> a == b False >>> a is b False >>> [1, 2, 3, 4] == [4, 1, 3, 2] False
Произвольные объекты в списках
Список может содержать любой набор объектов. Все элементы списка могут быть одного типа:
>>> a = [2, 4, 6, 8] >>> a [2, 4, 6, 8]
Или же элементы могут быть разных типов:
>>> a = [21.42, 'foobar', 3, 4, 'bark', False, 3.14159] >>> a [21.42, 'foobar', 3, 4, 'bark', False, 3.14159]
Списки могут даже содержать сложные объекты, такие как функции, классы и модули, о которых вы узнаете в следующих учебных пособиях:
>>> int <class 'int'> >>> len >>> def foo(): ... pass ... >>> foo >>> import math >>> math <module 'math' (built-in)> >>> a = [int, len, foo, math] >>> a [<class 'int'>, , , <module 'math' (built-in)>]
Список может содержать любое количество объектов, от нуля до столько, сколько позволит память вашего компьютера:
>>> a = [] >>> a [] >>> a = [ 'foo' ] >>> a ['foo'] >>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ... 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, ... 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, ... 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, ... 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
(Список с одним объектом иногда называют одноэлементным списком.)
Объекты списка не обязательно должны быть уникальными. Данный объект может появляться в списке несколько раз:
>>> a = ['bark', 'meow', 'woof', 'bark', 'cheep', 'bark'] >>> a ['bark', 'meow', 'woof', 'bark', 'cheep', 'bark']
Доступ к элементам списка по индексу
Доступ к отдельным элементам списка осуществляется с помощью индекса в квадратных скобках. Это в точности аналогично доступу к отдельным символам в строке. Индексация списков основана на нуле, как и в случае со строками.
Рассмотрим следующий список:
>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge']
Индексы для элементов в a показаны ниже:
Вот код Python для доступа к некоторым элементам a:
>>> a[0] 'foo' >>> a[2] 'baz' >>> a[5] 'corge'
Практически все, что касается индексации строк, работает аналогично для списков. Например, отрицательный индекс списка отсчитывается с конца списка:
>>> a[-1] 'corge' >>> a[-2] 'quux' >>> a[-5] 'bar'
Нарезка тоже работает. Если a является списком, то выражение a[m:n] возвращает часть a из индекса m в индекс n, но не включая его:
>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> a[2:5] ['baz', 'qux', 'quux']
- Другие особенности нарезки строк работают аналогично и для нарезки списков:
>>> a[-5:-2] ['bar', 'baz', 'qux'] >>> a[1:4] ['bar', 'baz', 'qux'] >>> a[-5:-2] == a[1:4] True
- Пропуск первого индекса запускает срез в начале списка, а пропуск второго индекса расширяет срез до конца списка:
>>> print(a[:4], a[0:4]) ['foo', 'bar', 'baz', 'qux'] ['foo', 'bar', 'baz', 'qux'] >>> print(a[2:], a[2:len(a)]) ['baz', 'qux', 'quux', 'corge'] ['baz', 'qux', 'quux', 'corge'] >>> a[:4] + a[4:] ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> a[:4] + a[4:] == a True
- Вы можете указать шаг—либо положительный, либо отрицательный:
>>> a[0:6:2] ['foo', 'baz', 'quux'] >>> a[1:6:2] ['bar', 'qux', 'corge'] >>> a[6:0:-2] ['corge', 'qux', 'bar']
- Синтаксис реверсирования списка работает так же как и для строк:
>>> a[::-1] ['corge', 'quux', 'qux', 'baz', 'bar', 'foo']
- Синтаксис [:] работает для списков. Однако существует важное различие между тем, как эта операция работает со списком, и тем, как она работает со строкой.
Если s это строка, s[:] то она возвращает ссылку на тот же объект:>>> s = 'foobar' >>> s[:] 'foobar' >>> s[:] is s True
И наоборот, если a это список, a[:] возвращает новый объект, который является копией a:
>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> a[:] ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> a[:] is a False
Некоторые операторы Python и встроенные функции также могут использоваться со списками аналогично строкам:
- In и not in операторы:
>>> a ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> 'qux' in a True >>> 'thud' not in a True
- Операторы конкатенации (+) и репликации (*) :
>>> a ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> a + ['grault', 'garply'] ['foo', 'bar', 'baz', 'qux', 'quux', 'corge', 'grault', 'garply'] >>> a * 2 ['foo', 'bar', 'baz', 'qux', 'quux', 'corge', 'foo', 'bar', 'baz', 'qux', 'quux', 'corge']
- Функции len(), min(), иmax():
>>> a ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> len(a) 6 >>> min(a) 'bar' >>> max(a) 'qux'
Это не случайность, что строки и списки ведут себя так же. Они оба являются частными случаями более общего типа объекта, называемого iterable, с которым вы столкнетесь более подробно в предстоящем учебнике по определенной итерации.
Кстати, в каждом приведенном выше примере список всегда присваивается переменной перед выполнением над ней операции. Но вы также можете оперировать литералом списка:
>>> ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'][2] 'baz' >>> ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'][::-1] ['corge', 'quux', 'qux', 'baz', 'bar', 'foo'] >>> 'quux' in ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] True >>> ['foo', 'bar', 'baz'] + ['qux', 'quux', 'corge'] ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> len(['foo', 'bar', 'baz', 'qux', 'quux', 'corge'][::-1]) 6
В этом случае вы можете сделать то же самое со строковым литералом:
>>> 'If Comrade Napoleon says it, it must be right.'[::-1] '.thgir eb tsum ti ,ti syas noelopaN edarmoC fI'
Вложенные списки
Вы видели, что элемент в списке может быть любым видом объекта. Это включает в себя еще один список. Список может содержать подсписки, которые в свою очередь могут содержать сами подсписки, и так далее до произвольной глубины.
Рассмотрим этот (по общему признанию надуманный) пример:
>>> x = ['a', ['bb', ['ccc', 'ddd'], 'ee', 'ff'], 'g', ['hh', 'ii'], 'j'] >>> x ['a', ['bb', ['ccc', 'ddd'], 'ee', 'ff'], 'g', ['hh', 'ii'], 'j']
Структура объекта, на которую ссылается x, изображена на диаграмме ниже:
x[0], x[2] и x[4] - это строки длиной по одному символу:
>>> print(x[0], x[2], x[4]) a g j
Но x[1] и x[3] - это подсписки:
>>> x[1] ['bb', ['ccc', 'ddd'], 'ee', 'ff'] >>> x[3] ['hh', 'ii']
Чтобы получить доступ к элементам в подсписке, просто добавьте дополнительный индекс:
>>> x[1] ['bb', ['ccc', 'ddd'], 'ee', 'ff'] >>> x[1][0] 'bb' >>> x[1][1] ['ccc', 'ddd'] >>> x[1][2] 'ee' >>> x[1][3] 'ff' >>> x[3] ['hh', 'ii'] >>> print(x[3][0], x[3][1]) hh ii
x[1][1] это еще один подсписок, поэтому добавление еще одного индекса обращается к его элементам:
>>> x[1][1] ['ccc', 'ddd'] >>> print(x[1][1][0], x[1][1][1]) ccc ddd
Нет никаких ограничений, кроме объема памяти вашего компьютера, на глубину или сложность, с которой списки могут быть вложены таким образом.
Весь обычный синтаксис касающийся индексов и нарезки также применим к подспискам:
>>> x[1][1][-1] 'ddd' >>> x[1][1:3] [['ccc', 'ddd'], 'ee'] >>> x[3][::-1] ['ii', 'hh']
Однако имейте в виду, что операторы и функции применяются только к списку на указанном вами уровне и не являются рекурсивными. Рассмотрим, что происходит, когда вы запрашиваете длину x использования len():
>>> x ['a', ['bb', ['ccc', 'ddd'], 'ee', 'ff'], 'g', ['hh', 'ii'], 'j'] >>> len(x) 5 >>> x[0] 'a' >>> x[1] ['bb', ['ccc', 'ddd'], 'ee', 'ff'] >>> x[2] 'g' >>> x[3] ['hh', 'ii'] >>> x[4] 'j'
x имеет всего пять элементов—три строки и два подсписка. Отдельные элементы в подсписках не учитываются в xзависимости от их длины.
Вы могли бы столкнуться с аналогичной ситуацией при использовании inоператора:
>>> 'ddd' in x False >>> 'ddd' in x[1] False >>> 'ddd' in x[1][1] True
'ddd' не является одним из элементов в x или x[1]. Это только непосредственно элемент в подлист x[1][1]. Отдельный элемент в подлисте не считается элементом родительского списка(списков).
Изменение списков
Большинство типов данных, с которыми вы сталкивались до сих пор, были атомарными. Целочисленные или плавающие объекты, например, являются примитивными единицами, которые не могут быть далее разбиты. Эти типы неизменяемы, что означает, что они не могут быть изменены, как только они были назначены. Нет особого смысла думать об изменении значения целого числа. Если вам нужно другое целое число, вы просто назначаете другое.
Напротив, строковый тип является составным типом. Строки можно свести к более мелким частям—компонентам символов. Возможно, имеет смысл подумать об изменении символов в строке. Но ты не можешь. В Python строки также являются неизменяемыми.
Этот список является первым изменяемым типом данных, с которым вы столкнулись. После того, как список был создан, элементы могут быть добавлены, удалены, сдвинуты и перемещены по желанию. Python предоставляет широкий спектр способов изменения списков.
Динамические списки
Этот учебник начался со списка из шести определяющих характеристик списков Python. Последний - это то, что списки являются динамическими. Вы видели много примеров этого в разделах выше. Когда элементы добавляются в список, он растет по мере необходимости:
>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> a[2:2] = [1, 2, 3] >>> a += [3.14159] >>> a ['foo', 'bar', 1, 2, 3, 'baz', 'qux', 'quux', 'corge', 3.14159]
Аналогично, список сокращается, чтобы вместить удаление элементов:
>>> a = ['foo', 'bar', 'baz', 'qux', 'quux', 'corge'] >>> a[2:3] = [] >>> del a[0] >>> a ['bar', 'qux', 'quux', 'corge']
Кортежи Python
Python предоставляет еще один тип, представляющий собой упорядоченную коллекцию объектов, называемую кортежем.
Произношение меняется в зависимости от того, кого вы спрашиваете. Одни произносят его так, как будто оно пишется “too-ple” (рифмуется с “Mott the Hoople”), а другие так, как будто оно пишется “tup-ple” (рифмуется с “supple”). Я склоняюсь к последнему, так как оно, по-видимому, происходит от того же происхождения, что и “квинтупль”, “секступль”, “октупль” и т. д., И все, кого я знаю, произносят эти последние так, как будто они рифмуются с “гибким".”
Определение и использование кортежей
Python предоставляет еще один тип, представляющий собой упорядоченную коллекцию объектов, называемую кортежем.
Произношение меняется в зависимости от того, кого вы спрашиваете. Одни произносят его так, как будто оно пишется “too-ple” (рифмуется с “Mott the Hoople”), а другие так, как будто оно пишется “tup-ple” (рифмуется с “supple”). Я склоняюсь к последнему, так как оно, по-видимому, происходит от того же происхождения, что и “квинтупль”, “секступль”, “октупль” и т. д., И все, кого я знаю, произносят эти последние так, как будто они рифмуются с “гибким".”
Кортежи идентичны спискам во всех отношениях, за исключением следующих свойств:
- Кортежи определяются путем заключения элементов в круглые скобки (()) вместо квадратных скобок ([]).
- Кортежи неизменны.
Вот краткий пример, показывающий определение кортежа, индексацию и нарезку:
>>> t = ('foo', 'bar', 'baz', 'qux', 'quux', 'corge') >>> t ('foo', 'bar', 'baz', 'qux', 'quux', 'corge') >>> t[0] 'foo' >>> t[-1] 'corge' >>> t[1::2] ('bar', 'qux', 'corge')
Не бойтесь! Наш любимый механизм разворота строк и списков также работает для кортежей:
>>> t[::-1] ('corge', 'quux', 'qux', 'baz', 'bar', 'foo')
Примечание: даже если кортежи определяются с помощью круглых скобок, вы все равно индексируете и разрезаете кортежи с помощью квадратных скобок, как и для строк и списков.
Все, что вы узнали о списках—они упорядочены, они могут содержать произвольные объекты, они могут быть индексированы и нарезаны, они могут быть вложены—верно и для кортежей. Но они не могут быть изменены:
>>> t = ('foo', 'bar', 'baz', 'qux', 'quux', 'corge') >>> t[2] = 'Bark!' Traceback (most recent call last): File "<pyshell#65>", line 1, in t[2] = 'Bark!' TypeError: 'tuple' object does not support item assignment
Зачем использовать кортеж вместо списка?
- Выполнение программы происходит быстрее при манипулировании кортежем, чем для эквивалентного списка. (Это, вероятно, не будет заметно, когда список или кортеж невелики.)
- Иногда вы не хотите, чтобы данные были изменены. Если значения в коллекции должны оставаться постоянными в течение всего срока службы программы, использование кортежа вместо списка защищает от случайного изменения.
- Есть еще один тип данных Python, с которым вы вскоре столкнетесь, называемый словарем, который требует в качестве одного из своих компонентов значение, которое имеет неизменяемый тип. Кортеж может быть использован для этой цели, в то время как список не может быть.
В сеансе Python REPL можно отображать значения нескольких объектов одновременно, вводя их непосредственно в >>>приглашении, разделенные запятыми:
>>> a = 'foo' >>> b = 42 >>> a, 3.14159, b ('foo', 3.14159, 42)
Python отображает ответ в круглых скобках, поскольку он неявно интерпретирует входные данные как кортеж.
Существует одна особенность определения кортежа, о которой вы должны знать. Нет никакой двусмысленности при определении пустого кортежа, ни одного с двумя или более элементами. Python знает, что вы определяете кортеж:
>>> t = () >>> type(t) <class 'tuple'>
>>> t = (1, 2) >>> type(t) <class 'tuple'> >>> t = (1, 2, 3, 4, 5) >>> type(t) <class 'tuple'>
Но что происходит, когда вы пытаетесь определить кортеж с одним элементом:
>>> t = (2) >>> type(t) <class 'int'>
Поскольку круглые скобки также используются для определения приоритета операторов в выражениях, Python вычисляет выражение (2)как простое целое 2 число и создает int объект. Чтобы сказать Python, что вы действительно хотите определить одноэлементный кортеж, включите конечную запятую (,) непосредственно перед закрывающей скобкой:
>>> t = (2,) >>> type(t) <class 'tuple'> >>> t[0] 2 >>> t[-1] 2
Вероятно, вам не придется часто определять одноэлементный кортеж, но какой-то способ должен быть.
Когда вы показываете одноэлементный кортеж, Python включает запятую, чтобы напомнить вам, что это кортеж:
>>> print(t) (2,)
Назначение кортежа, упаковка и распаковка
Как вы уже видели выше, литеральный кортеж, содержащий несколько элементов, может быть назначен одному объекту:
>>> t = ('foo', 'bar', 'baz', 'qux')
Когда это происходит, создается впечатление, что элементы кортежа были “упакованы” в объект:
>>> t ('foo', 'bar', 'baz', 'qux') >>> t[0] 'foo' >>> t[-1] 'qux'
Если этот “упакованный” объект впоследствии присваивается новому кортежу, отдельные элементы “распаковываются” в объекты кортежа:
>>> (s1, s2, s3, s4) = t >>> s1 'foo' >>> s2 'bar' >>> s3 'baz' >>> s4 'qux'
При распаковке количество переменных слева должно совпадать с количеством значений в кортеже:
>>> (s1, s2, s3) = t Traceback (most recent call last): File "<pyshell#16>", line 1, in (s1, s2, s3) = t ValueError: too many values to unpack (expected 3) >>> (s1, s2, s3, s4, s5) = t Traceback (most recent call last): File "<pyshell#17>", line 1, in (s1, s2, s3, s4, s5) = t ValueError: not enough values to unpack (expected 5, got 4)
Упаковка и распаковка могут быть объединены в один оператор чтобы сделать сложное назначение:
>>> (s1, s2, s3, s4) = ('foo', 'bar', 'baz', 'qux') >>> s1 'foo' >>> s2 'bar' >>> s3 'baz' >>> s4 'qux'
Опять же, число элементов в кортеже слева от присваивания должно быть равно числу справа:
>>> (s1, s2, s3, s4, s5) = ('foo', 'bar', 'baz', 'qux') Traceback (most recent call last): File "<pyshell#63>", line 1, in (s1, s2, s3, s4, s5) = ('foo', 'bar', 'baz', 'qux') ValueError: not enough values to unpack (expected 5, got 4)
В таких заданиях, как это и небольшая горстка других ситуаций, Python позволяет оставить скобки, которые обычно используются для обозначения кортежа:
>>> t = 1, 2, 3 >>> t (1, 2, 3) >>> x1, x2, x3 = t >>> x1, x2, x3 (1, 2, 3) >>> x1, x2, x3 = 4, 5, 6 >>> x1, x2, x3 (4, 5, 6) >>> t = 2, >>> t (2,)
Он работает одинаково независимо от того, включены ли круглые скобки или нет, поэтому, если у вас есть какие-либо сомнения относительно того, нужны ли они, продолжайте и включите их.
Назначение кортежей позволяет получить любопытный бит идиоматического Python. Часто при программировании у вас есть две переменные, значения которых нужно поменять местами. В большинстве языков программирования необходимо хранить одно из значений во временной переменной, в то время как своп происходит следующим образом:
>>> a = 'foo' >>> b = 'bar' >>> a, b ('foo', 'bar') >>># We need to define a temp variable to accomplish the swap. >>> temp = a >>> a = b >>> b = temp >>> a, b ('bar', 'foo')
В Python подкачка может быть выполнена с помощью одного назначения кортежа:
>>> a = 'foo' >>> b = 'bar' >>> a, b ('foo', 'bar') >>># Magic time! >>> a, b = b, a >>> a, b ('bar', 'foo')
Как известно любому, кому когда-либо приходилось менять значения с помощью временной переменной, возможность сделать это таким образом в Python - это вершина современных технологических достижений. Лучше этого уже никогда не будет.
Заключение
В этом уроке были рассмотрены основные свойства Python списков и кортежей, а также способы манипулирования ими. Вы будете широко использовать их в своем программировании на Python.
Одна из главных характеристик списка состоит в том, что он упорядочен. Порядок элементов в списке является внутренним свойством этого списка и не изменяется, если сам список не изменяется. (То же самое верно и для кортежей, за исключением того, что они, конечно, не могут быть изменены.)
В следующем уроке вы познакомитесь со словарем Python: составным типом данных, который является неупорядоченным. Читайте дальше!