Это старая версия документа!


Перечислимые типы (iterable)

Базовые перечислимые типы

Тип Название Объявление Порядок
list Список
[1, 2, 1], ["a", "b", "a"], []
Да
tuple Кортеж
(1, 2, 1), ("a", "b", "a"), ("a",)
Да
set Набор
{1, 3, 2}, {"a","c","b"}, set()
Нет
dict Словарь
{"a":1, "c":2, "b":1}, {}
Нет

Перечислимые типы являются изменяемыми (mutable). При присвоении переменные этих типов не копируются.

Типы tuple, str и bytes имеют промежуточный статус. Они является неизменяемыми, но переменные этих типов можно перечислять.

Особенности перечислимых типов

  • Элементы перечислимых типов могут быть произвольного, в том числе перечислимого типа:
data = [5,7,9,12,"test",True,["ab","cd","ef"]]
  • Списки и кортежи сохраняют порядок, а наборы и словари - нет:
data_list = [5,4,3,6,2,1]
data_set = {5,4,3,6,2,1}
print(data_list) # [5, 4, 3, 6, 2, 1]
print(data_set) # {1, 2, 3, 4, 5, 6}
  • Переменные перечислимых типов (как и все составных) при присвоении не копируются:
data = [5,7,9,12]
double_data = data
double_data[1] = 42
print(data) # [5, 42, 9, 12]
  • Переменные перечислимых типов можно перечислять.

Итерационный цикл for

Цикл for используется для перебора элементов в переменных перечислимых типов.

Синтаксис:

for <новая переменная> in <переменная перечислимого типа> :
␣␣␣␣<оператор>
␣␣␣␣<оператор>

Примеры:

data = ['a', 'b', 'c', 'd']
for x in data:
    print(x)

Список: list

  • Используется в качестве замены массивам и векторам
  • Может иметь произвольную длину
  • Его можно удлинять и укорачивать

Индексирование списков

Индексирование в Python выполняется с 0.

data = ['a', 'b', 'c', 'd']
data[0] # 'a'
data[3] # 'd'
data[4] # Ошибка: выход за пределы списка
# Отрицательные индексы нумеруют список с конца и с -1
data[-1] # 'd'
data[-4] # 'a'
# Длина
x = len(data) # x == 4
# Поиск по значению
x = data.index('c') # x == 2

Срезы списков

Срезы (slices) — это способ получать из списка его часть не прибегая к циклам.

Синтаксис:

<индекс первого элемента>:<индекс последнего элемента +1>

<индекс первого элемента>:<индекс последнего элемента +1>:<шаг>

data = ['a', 'b', 'c', 'd']
data[1:3] # ['b', 'c']
data[2:] # ['c', 'd']
data[:] # ['a', 'b', 'c', 'd']
data[-2:] # ['c', 'd']
data[1:4:2] # ['b', 'd']

Срезы создают копию списка.

data = ['a', 'b', 'c', 'd']

# нет копирования temp и data это один список с двумя именами
temp = data
temp[0] = 'z' # data[0] == 'z'

# есть копирование temp и data это разные списки
temp = data[:]
temp[0] = 'z' # data[0] == 'a'

Модификация списков

Изменения в самом списке:

data = ['a', 'b', 'c', 'd']
data[1] = 42 # data == ['a', 42, 'c', 'd']
del data[1] # data == ['a', 'c', 'd']
data.insert(0,42) # data == [42, 'a', 'c', 'd']
data.append(42) # data == [42, 'a', 'c', 'd', 42]
data = data + [1,2,3]
# data == [42, 'a', 'c', 'd', 42, 1, 2, 3]
v = data.pop()
# v == 3, data == [42, 'a', 'c', 'd', 42, 1, 2] 
v = data.pop(0)
# v == 42, data == ['a', 'c', 'd', 42, 1, 2]

Обход списков

data = ['a', 'b', 'c', 'd']
for v in data:
    print(v) # a b c d
for i,v in enumerate(data):
    print(i,v) # 0 a 1 b 2 c 3 d

Если элемент списка неизменяемого типа, то при присвоение переменной созданной в цикле for (в примере, v) нового значение не меняет содержание массива.

i = 0
while i < len(data):
    data[i] = 42
    i += 1
    
for i in range(0,len(data)):
    data[i] = 42

Явное изменение списка.

Кортеж: tuple

Кортеж это неизменяемый список.

tple = (1, 2, 3)
tple[0] # 1
tple[0] = 0 # Ошибка
tple.append(0) # Ошибка

Набор: set

Набор не сохраняет порядок. Все элементы набора различны.

vset = {4, 3, 2, 3, 1}
print(vset) # {1, 2, 3, 4}
vset[0] # Ошибка
vset.add(0) # {0, 1, 2, 3, 4}
vset.add(4) # {0, 1, 2, 3, 4}
vset.remove(4) # {0, 1, 2, 3}

Типичное применение — удаление дубликатов из списка:

data = [1, 1, 2, 2, 2]
data = list(set(data)) # [1, 2]

Словарь: dict

  • Набор пар ключ-значение. Ключи всегда различны.
  • Значения могут быть любого типа, ключи — с некоторыми ограничениями.
data = {"a":1, "b":2, "c":3}
data["b"] # 2

Модификация словарей

data = {"a":1, "b":2, "c":3}
data["b"] = 3 # data == {"a":1, "b":3, "c":3}
del data["b"] # data == {"a":1, "c":3}
data["f"] = 99 # data == {'a': 1, 'f': 99, 'c': 3}
x = len(data) # x == 3
data.update({"a":99, "q":64})
# data == {'a': 99, 'f': 99, 'q': 64, 'c': 3}

Обход словарей

data = {"a":1, "b":2, "c":3}

for k in data:
    print(k) # a c b
    print(data[k]) # 1 3 2

for k in sorted(data.keys()):
    print(k,data[k]) # a 1 b 2 c 3

Копирование переменных составных типов

При присвоении переменные составных типов (и в частности перечислимых) не копируются:

data = {"a":1, "b":2, "c":3}
new_data = data
new_data["a"] = 42
print(data["a"]) # 42 !!!

Копирование переменных составных типов

Для их копирования используются срезы и методы copy и deepcopy из модуля copy:

import copy

data = {"a":1, "b":2, "c":3}
new_data = copy.copy(data) # Поверхностная копия
new_data["a"] = 42
print(data["a"]) # 1

data = {"a":1, "b":[2,3,4], "c":3}
new_data = copy.deepcopy(data) # Полная копия
new_data["b"][0] = 42
print(data["b"]) # [2,3,4]

Сортировка списков

adata = [5,4,2,1,4]
# Сортировка с копированием
bdata = sorted(adata) # bdata == [1, 2, 4, 4, 5]
# Сортировка на месте (in-place)
adata.sort() # adata == [1, 2, 4, 4, 5]
# Обратная сортировка
bdata = sorted(adata, reverse=True) #[5, 4, 4, 2, 1]
adata.sort(reverse=True) #[5, 4, 4, 2, 1]

Приведение перечислимых типов

Исходный тип data
Целевой тип list tuple set dict
list = list(data) list(data) list(data.keys()), list(data.values())
tuple tuple(data) = tuple(data) tuple(data.keys()), tuple(data.values())
set set(data) set(data) = set(data.keys()), set(data.values())
dict dict(zip(keys,data)) dict(zip(keys,data)) dict(zip(keys,data)) =