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

Таким образом, первый элемент имеет индекс 0, второй элемент имеет индекс 1 и так далее.

Python имеет встроенные изменяемые и неизменяемые типы последовательностей.

Строки и кортежи неизменяемы — мы можем получить доступ, но не можем изменить содержимое последовательности:

In:

t = (1, 2, 3)
t[0]

Вне:

1

In:

t[0] = 100
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-155b9e8fb284> in <module>()
----> 1 t[0] = 100
TypeError: 'tuple' object does not support item assignment

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

In:

t = ( [1, 2], 3, 4)

t неизменяем, но его первый элемент является изменяемым объектом:

In:

t[0][0] = 100
t

Вне:

([100, 2], 3, 4)

Итерации

iterable — это просто то, что можно повторять, например, с помощью цикла for:

In:

t = (10, 'a', 1+3j)
s = {10, 'a', 1+3j}
for c in t:
print(c)
Out:
10
a
(1+3j)

In:

for c in s:
print(c)
Out:
a
10
(1+3j)

Обратите внимание, как мы могли перебирать как кортеж, так и набор. Повторение кортежа сохранило порядок элементов в кортеже, но не для набора. В наборах нет порядка элементов — они итерабельны, но не последовательности.

Большинство типов последовательностей поддерживают операции in и not in. Диапазоны тоже работают, но не так эффективно, как списки, кортежи, строки и т. д.

In:

'a' in ['a', 'b', 100]

Вне:

True

In:

100 in range(200)

Вне:

True

Мин., макс. и длина

Последовательности также обычно поддерживают метод len для получения количества элементов в коллекции. Некоторые итерации также могут поддерживать этот метод.

In:

len('python'), len([1, 2, 3]), len({10, 20, 30}), len({'a': 1, 'b': 2})

Вне:

(6, 3, 3, 2)

Последовательности (и даже некоторые итерации) могут поддерживать max и min, если типы данных в коллекции могут быть в некотором смысле упорядочены (< или >).

In:

a = [100, 300, 200]
min(a), max(a)

Вне:

(100, 300)

In:

s = 'python'
min(s), max(s)

Вне:

('h', 'y')

In:

s = {'p', 'y', 't', 'h', 'o', 'n'}
min(s), max(s)

Вне:

('h', 'y')

Но если элементы не имеют определенного порядка:

In:

a = [1+1j, 2+2j, 3+3j]
min(a)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-17-b0cd79e53377> in <module>()
      1 a = [1+1j, 2+2j, 3+3j]
----> 2 min(a)
TypeError: '<' not supported between instances of 'complex' and 'complex'

min и max будут работать для разнородных типов, если элементы попарно сравнимы (определены < или >).

Например:

In:

from decimal import Decimal
t = 10, 20.5, Decimal('30.5')
min(t), max(t)

Вне:

(10, Decimal('30.5'))

In:

t = ['a', 10, 1000]
min(t)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-983eac063887> in <module>()
      1 t = ['a', 10, 1000]
----> 2 min(t)
TypeError: '<' not supported between instances of 'int' and 'str'

Даже объекты range поддерживают min и max:

In:

r = range(10, 200)
min(r), max(r)

Вне:

(10, 199)

Конкатенация

Мы можем объединять последовательности с помощью оператора +:

In:

[1, 2, 3] + [4, 5, 6]

Вне:

[1, 2, 3, 4, 5, 6]

In:

(1, 2, 3) + (4, 5, 6)

Вне:

(1, 2, 3, 4, 5, 6)

Обратите внимание, что тип объединенного результата совпадает с типом объединяемых последовательностей, поэтому объединение последовательностей разных типов не будет работать:

In:

(1, 2, 3) + [4, 5, 6]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-25-67a9e2ed8695> in <module>()
----> 1 (1, 2, 3) + [4, 5, 6]
TypeError: can only concatenate tuple (not "list") to tuple

In:

'abc' + ['d', 'e', 'f']
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-26-8cbdd441adc1> in <module>()
----> 1 'abc' + ['d', 'e', 'f']
TypeError: must be str, not list

Примечание: если вы действительно хотите объединить различные типы, вам придется сначала преобразовать их в общий тип:

In:

(1, 2, 3) + tuple([4, 5, 6])

Вне:

(1, 2, 3, 4, 5, 6)

In:

tuple('abc') + ('d', 'e', 'f')

Вне:

('a', 'b', 'c', 'd', 'e', 'f')

In:

''.join(tuple('abc') + ('d', 'e', 'f'))

Вне:

'abcdef'

Повторение

Большинство типов последовательностей также поддерживают повторение, то есть объединение одной и той же последовательности целое число раз:

In:

'abc' * 5

Вне:

'abcabcabcabcabc'

In:

[1, 2, 3] * 5

Вне:

[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

Чуть позже мы вернемся к некоторым предостережениям относительно конкатенации и повторения.

Поиск вещей в последовательностях

Мы можем найти индекс вхождения элемента в последовательность:

In:

s = "gnu's not unix"
s.index('n')

Вне:

1

In:

s.index('n', 1), s.index('n', 2), s.index('n', 8)

Вне:

(1, 6, 11)

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

In:

s.index('n', 13)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-35-d038ca109973> in <module>()
----> 1 s.index('n', 13)
ValueError: substring not found

In:

try:
idx = s.index('n', 13)
except ValueError:
print('not found')
Out:
not found

Обратите внимание, что эти методы поиска объектов в последовательностях не предполагают, что объекты в последовательности каким-либо образом упорядочены. В основном они выполняют поиск, который перебирает последовательность, пока не найдет (или не найдет) запрошенный элемент.

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

Нарезка

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

In:

s = 'python'
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
s[0:3], s[4:6]

Вне:

('pyt', 'on')

In:

l[0:3], l[4:6]

Вне:

([1, 2, 3], [5, 6])

Можно расширять диапазоны за пределы последовательности:

In:

s[4:1000]

Вне:

'on'

Если ваш первый аргумент в срезе — 0, вы можете его даже опустить. Отсутствие второго аргумента означает, что он будет включать все остальные элементы:

In:

s[0:3], s[:3]

Вне:

('pyt', 'pyt')

In:

s[3:1000], s[3:], s[:]

Вне:

('hon', 'hon', 'python')

У нас даже может быть расширенная нарезка, которая обеспечивает начало, остановку и шаг:

In:

s, s[0:5], s[0:5:2]

Вне:

('python', 'pytho', 'pto')

In:

s, s[::2]

Вне:

('python', 'pto')

Технически мы также можем использовать отрицательные значения в срезах, включая расширенные срезы (подробнее об этом позже):

In:

s, s[-3:-1], s[::-1]

Вне:

('python', 'ho', 'nohtyp')

In:

r = range(11)  # numbers from 0 to 10 (inclusive)
print(r)
print(list(r))
Out:
range(0, 11)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In:

print(r[:5])
Out:
range(0, 5)

In:

print(list(r[:5]))
[0, 1, 2, 3, 4]

Как видите, разрезание диапазона также возвращает объект диапазона, как и ожидалось.

Хеширование

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

In:

l = (1, 2, 3)
hash(l)

Вне:

2528502973977326415

In:

s = '123'
hash(s)

Вне:

-1892188276802162953

In:

r = range(10)
hash(r)

Вне:

-6299899980521991026

Но изменяемые последовательности (и изменяемые типы в целом) этого не делают:

In:

l = [1, 2, 3]
hash(l)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-54-22dd9c98a095> in <module>()
----> 1 hash(l)
TypeError: unhashable type: 'list'

Также обратите внимание, что хешируемая последовательность больше не является хэшируемой, если один (или несколько) ее элементов не хешируются:

In:

t = (1, 2, [10, 20])
hash(t)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-55-30cac1c4a226> in <module>()
      1 t = (1, 2, [10, 20])
----> 2 hash(t)
TypeError: unhashable type: 'list'

Но это сработает:

In:

t = ('python', (1, 2, 3))
hash(t)

Вне:

-8790163410081325536

Как правило, неизменяемые типы, скорее всего, хэшируются, а неизменяемые — нет. Таким образом, числа, строки, кортежи и т. д. можно хэшировать, а списки и наборы — нет:

In:

from decimal import Decimal
d = Decimal(10.5)
hash(d)

Вне:

1152921504606846986

Наборы не хэшируются:

In:

s = {1, 2, 3}
hash(s)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-58-2216931a6bc4> in <module>()
      1 s = {1, 2, 3}
----> 2 hash(s)
TypeError: unhashable type: 'set'

Но замороженные наборы, неизменный вариант набора, это:

In:

s = frozenset({1, 2, 3})
hash(s)

Вне:

-7699079583225461316

Предостережения относительно конкатенации и повторения

Учти это:

In:

x = [2000]
id(x[0])

Вне:

2177520743920

In:

l = x + x
l

Вне:

[2000, 2000]

In:

id(l[0]), id(l[1])

Вне:

(2177520743920, 2177520743920)

Как и ожидалось, объекты в l[0] и l[1] одинаковы.

Можно также использовать:

In:

l[0] is l[1]

Вне:

True

Это не имеет большого значения, если объединяемые объекты неизменяемы. Но если они изменчивы:

In:

x = [ [0, 0] ]
l = x + x
l

Вне:

[[0, 0], [0, 0]]

In:

l[0] is l[1]

Вне:

True

И тогда мы имеем следующее:

In:

l[0][0] = 100
l[0]

Вне:

[100, 0]

In:

l

Вне:

[[100, 0], [100, 0]]

Обратите внимание, как изменение 1-го элемента 1-го элемента также изменило 1-й элемент второго элемента.

Хотя это кажется довольно очевидным при конкатенации с использованием оператора +, как мы только что сделали, то же самое на самом деле происходит с повторением и может показаться не столь очевидным:

In:

x = [ [0, 0] ]
m = x * 3
m

Вне:

[[0, 0], [0, 0], [0, 0]]

In:

m[0][0] = 100
m

Вне:

[[100, 0], [100, 0], [100, 0]]

А ведь даже x изменился:

In:

x

Вне:

[[100, 0]]

Если вы действительно хотите, чтобы эти повторяющиеся объекты были разными объектами, вам придется как-то их копировать. Здесь хорошо сработает простое понимание списка:

In:

x = [ [0, 0] ]
m = [e.copy() for e in x*3]
m

Вне:

[[0, 0], [0, 0], [0, 0]]

In:

m[0][0] = 100
m

Вне:

[[100, 0], [0, 0], [0, 0]]

In:

x

Вне:

[[0, 0]]