📦 Репозиторий занятия 24

Урок 24. Кортежи

Как работать с репозиторием

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

Маршрут изучения

  1. Прочитайте описание: по нему уже понятно, о чём файл и что он выведет.
  2. Предскажите вывод: сравните своё предположение со строкой «Что выводит».
  3. Запустите: скачайте файл или скопируйте код кнопкой и выполните его у себя.
  4. Измените: поменяйте одно условие или значение и объясните новый результат.

Файлы: рекомендуемый порядок

1
MarkdownРазбор концепции207 строк

Тюпл (tuple): неизменяемая коллекция, синтаксис, методы, конкатенация

less_13__tuple__sequence_assignment__packing_unpacking__enumerate/theory_01__tuple.md

Определяет тюпл как «неизменяемый список», разбирает синтаксис создания (с запятой для одного элемента, обязательными скобками для пустого тюпла, без скобок для нескольких значений через запятую) и пять базовых свойств (упорядоченность, неизменяемость, вложенность, дубли, срезы). Показывает TypeError при попытке t[0] = 10, два метода тюпла (count, index), конкатенацию и повторение по аналогии со строками, а также важную оговорку: t1 + (1) кидает TypeError, потому что (1) — не тюпл, а просто число в скобках. Завершается двумя парными «вопросами на засыпку» про тюпл со вложенным списком: что будет с тюплом, если список внутри изменить через += (мутация) против переприсвоить через = (rebind).

  • tuple('abc') → ('a','b','c'), tuple(5) → TypeError
  • Синтаксис: (5,) с запятой, () пустой, 1, 2, 3 без скобок
  • t[0] = 10 → TypeError: tuple не поддерживает item assignment
  • tuple.count(x) и tuple.index(x[, start[, end]])
  • t1 + t2 — конкатенация; t1 + (1) → TypeError (1 не тюпл)
  • t1 * 2 — повторение, len(t1), 3 in t1
  • Вопрос 1: lst += [3] внутри тюпла — тюпл «видит» изменение
  • Вопрос 2: lst = [1,2,3] (переприсвоение) — тюпл НЕ видит изменение
Показать начало файла (207 строк всего)
## Определение

**Тюпл (tuple)** — это неизменяемая (immutable) упорядоченная коллекция объектов.

(Грубо, но почти точно: **"тюпл - это неизменяемый список"**)

## `tuple()` - функция создания тюпла из коллекции

По аналогии с функцией `list()`:

```python
print(tuple('abc'))    # ('a', 'b', 'c')

print(tuple(5))
# TypeError: 'int' object is not iterable
```

## Синтаксис

* Последовательность, разделённая запятыми
* Может дополнительно браться в круглые скобки `()`
* Если элемент всего один - запятая обязательна 
* Если тюпл пустой - скобки обязательны

* Записывается через круглые скобки `()`
* Может содержать элементы разных типов и повторяющиеся элементы
* Поддерживает индексацию и слайсинг (срезы)

Пример:

```python
# пустой тюпл
t0 = ()
print(t0)  # ()

t1 = tuple()
print(t1)  # ()

# один элемент (запятая обязательна!)
t2 = (5,)
print(t2)  # (5,)

# без скобок
t3 = 1, 2, 3
print(t3)  # (1, 2, 3)

# со скобками
t4 = ("a", "b", "c")
print(t4)  # ('a', 'b', 'c')

# элементы разных типов
t5 = 1, "hello", 3.14, True, (1,)
print(t5)  # (1, 'hello', 3.14, True, (1,))
```

---

## Основные свойства тюпла

1. **Упорядоченность** — элементы имеют фиксированный порядок.
…
Проверьте себя: В чём разница между вопросом №1 (lst += [3]) и вопросом №2 (lst = [1, 2, 3]) с точки зрения того, что видит тюпл t, содержащий ссылку на lst?
2
MarkdownРазбор концепции64 строк

Packing и unpacking: символ * для сборки и распаковки коллекций

less_13__tuple__sequence_assignment__packing_unpacking__enumerate/theory_02__packing_unpacking.md

Разделяет packing (упаковка нескольких объектов в одну коллекцию через *args) и unpacking (распаковка коллекции на отдельные элементы через *lst). Показывает *args в функции для суммирования произвольного числа аргументов и print(*lst) для распаковки списка в отдельные значения. Отдельно подчёркнуто ограничение: звёздочка разрешена только внутри последовательности или вызова функции — x = *lst вне этого контекста даёт SyntaxError.

  • def total_amount(*args): — packing аргументов функции в тюпл
  • print(*lst, sep='---') — unpacking списка при выводе
  • x = *lst → SyntaxError: can't use starred expression here
  • r2 = (*t1, *t2) — объединение двух списков через unpacking в новый тюпл
Показать начало файла (64 строк всего)
## Определение

**Packing** — упаковывание нескольких объектов в одну коллекцию (tuple, list, dict)  
с помощью символа `*` (или  `**`).

**Unpacking** — распаковка коллекции на отдельные объекты с помощью символа `*` (или `**`).

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

### Пример packing

`*args` запаковывает любое кол-во аргументов в один тюпл

```python
def total_amount(*args):
    # print(args)       # (2, 3, 4)
    # print(type(args)) # (2, 3, 4)
    print(sum(args))    # amount: 9


total_amount(2, 3, 4) # 9
```

### Пример unpacking

Звёздочка перед коллекцией распаковывает один объект (коллекцию) на элементы

```python
lst = [1, 2, 3]

print(lst, sep='---')
# [1, 2, 3]

print(*lst, sep='---')
# 1---2---3
```

## ВАЖНО!

`*` - символ пакинга / анпакинга, разрешён ТОЛЬКО:
    - внутри последовательности
    - внутри функции

```python
lst = [1, 2, 3]
x = *lst  

#      x = *lst
#          ^^^
# SyntaxError: can't use starred expression here
```

## Другие примеры

```python
t1 = [1, 2]
t2 = [3, 4, 5]

r1 = (t1, t2)
print(r1)   # ([1, 2], [3, 4, 5])
…
Проверьте себя: Чем (*t1, *t2) отличается от (t1, t2) — почему первый даёт плоский тюпл из 5 чисел, а второй — тюпл из двух списков?
3
MarkdownРазбор концепции44 строк

Распаковка последовательности (sequence assignment) и её связь с packing

less_13__tuple__sequence_assignment__packing_unpacking__enumerate/theory_03__sequence_assignment.md

Показывает множественное присваивание из строки/списка/тюпла в несколько переменных сразу, с жёстким требованием: количество переменных должно точно совпасть с числом элементов, иначе ValueError (too many / not enough values to unpack). Решение этой проблемы — packing через *rest, который собирает «остаток» элементов в список, что позволяет распаковывать последовательности переменной длины без ошибки.

  • a, b, c = 'ABC' — распаковка строки в три переменные
  • a, b = 'ABC' → ValueError: too many values to unpack
  • a, b, c, d = 'ABC' → ValueError: not enough values to unpack
  • a, b, *rest = 'ABC' — rest собирает остаток в список
  • a, b, c, *rest = 'ABC' — rest получается пустым списком
Показать начало файла (44 строк всего)
## Распаковка последовательности* (`iterable unpacking`)

    * Точнее будет "Распаковка итерируемого объекта". Поскольку не все итерируемые объекты являются последовательностями.

Это присваивание элементов последовательности (списка, тюпла, строки)  
нескольким переменным одновременно.

Количество переменных должно СТРОГО совпадать с количеством элементов последовательности, иначе будет ошибка.

(Часто называется также ["Множественное присваивание" (`multiple assignment`)](../less_03__arithmetic_operations__type_conversion/theory_04__additional_types_of_assignments.md)

```python
a, b, c = 'ABC'
print('a:', a)  # A
print('b:', b)  # B
print('c:', c)  # C


a, b = 'ABC'
# ValueError: too many values to unpack (expected 2)


a, b, c, d = 'ABC'
# ValueError: not enough values to unpack (expected 4, got 3)
```

## Можно ли избежать ошибки в последних двух случаях?

ОТВЕТ: Да, если использовать packing.

```python

a, b, *rest = 'ABC'
print('a:', a)          # A
print('b:', b)          # B
print('rest:', rest)    # [C]


a, b, c, *rest = 'ABC'
print('a:', a)          # A
print('b:', b)          # B
print('c:', c)          # C
print('rest:', rest)    # []
```
Проверьте себя: Что вернёт rest в a, *rest, c = 'ABCDE' — то есть как ведёт себя *rest, если звёздочка стоит не в конце, а в середине?
4
MarkdownРазбор концепции28 строк

enumerate(): индекс и значение в одной итерации, параметр start

less_13__tuple__sequence_assignment__packing_unpacking__enumerate/theory_04__enumerate.md

Короткий файл про enumerate() как способ получить пару (индекс, значение) в цикле for без ручного счётчика, с примером на списке фруктов. Отдельно показан именованный параметр start, который сдвигает нумерацию с 0 на любое начальное значение (например 1) без изменения самого перебираемого списка.

  • for i, fruit in enumerate(fruits): — индекс с 0 по умолчанию
  • enumerate(fruits, start=1) — нумерация с 1
Показать начало файла (28 строк всего)
## Удобное сочетание индекса и значения в одной итерации


```python
fruits = ['apple', 'lemon', 'orange']

for i, fruit in enumerate(fruits):
    print(i, fruit)


# 0 apple
# 1 lemon
# 2 orange
```

## Установка начального значения индекса

```python
fruits = ['apple', 'lemon', 'orange']

for i, fruit in enumerate(fruits, start=1):
    print(i, fruit)


# 1 apple
# 2 lemon
# 3 orange
```
Проверьте себя: Если enumerate(fruits, start=-1) применить к списку из 3 элементов, какие будут значения i на каждой итерации?
5
MarkdownРазбор концепции19 строк

Тюпл со вложенным списком: id() как доказательство совместного изменения

less_13__tuple__sequence_assignment__packing_unpacking__enumerate/theory_05__mutable_vs_immutable.md

Развёрнутое пояснение к первому «вопросу на засыпку» из theory_01__tuple.md: тюпл t = (n1, n2, lst) хранит ссылки, а не копии, поэтому id(t[2]) совпадает с id(lst). Файл печатает id() каждого элемента до и после операции над lst и показывает итоговое содержимое t, наглядно демонстрируя, почему неизменяемость тюпла не защищает от изменения вложенного mutable-объекта, на который он ссылается.

  • t = (n1, n2, lst) — тюпл хранит ссылки, не копии
  • id(n1), id(n2), id(lst) == id(t[0]), id(t[1]), id(t[2])
  • Изменение lst и повторная печать t — тюпл отражает изменение вложенного объекта
  • print(t) в итоге показывает обновлённый список внутри неизменяемого тюпла
Показать начало файла (19 строк всего)
### Пояснения к [./theory_01__tuple.md](theory_01__tuple.md)

```python
n1, n2, lst = 1, 2, [1, 2]

t = (n1, n2, lst)

print(t)         # (1, 2, [1, 2])
print(type(t))   # <class 'tuple'>

print(id(n1), id(n2), id(lst))       # 12216648 12216680 140492792400640
print(id(t[0]), id(t[1]), id(t[2]))  # 12216648 12216680 140492792400640

lst = [1, 2, 3]
print(lst)      # [1, 2, 3]
print(id(lst))  # 140492792400640

print(t)  # (1, 2, [1, 2, 3])
```
Проверьте себя: Если бы вместо list внутри тюпла лежал tuple (тоже immutable), можно ли было бы получить тот же эффект «изменения» элемента t, как в этом примере?