📖 Теория: знакомство со списками

⚡ Кратко

Список — упорядоченная изменяемая коллекция элементов любых типов. Элементы можно читать и менять по индексу, извлекать срезами, объединять +, повторять *, проверять in и перебирать циклом for.

  • Создание: [], list(), list("abc"), list(range(...)).
  • Индексация: my_list[0], my_list[-1]; ошибка — выход за границы.
  • Срезы: my_list[1:4], my_list[::2], my_list[::-1].
  • Изменение: my_list[i] = x, my_list[i:j] = [a, b].
  • Циклы: for item in my_list: и вложенные циклы по списку строк.

Коллекции

Коллекция — это структура данных, которая позволяет хранить и организовывать множество элементов. В Python встроено несколько типов коллекций: list, tuple, set, dict, str и другие. Каждый тип подходит для разных задач. В этом уроке focus на списках.

Изменяемые типы данных

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

📄 examples/mutable_vs_immutable.py
# List is mutable
my_list = [1, 2, 3]
my_list[0] = 100
print(my_list)  # [100, 2, 3]

# String is immutable
text = "hello"
# text[0] = "H"  # TypeError

Список (list)

Список (list) — это упорядоченная изменяемая коллекция, которая может содержать элементы любых типов. Это одна из самых универсальных структур данных в Python.

Основные характеристики списка:

  • Изменяемость — элементы можно изменять после создания.
  • Упорядоченность — элементы хранятся в порядке добавления.
  • Поддержка дубликатов — одинаковые элементы разрешены.
  • Поддержка разных типов — в одном списке могут быть числа, строки, логические значения, другие списки.
  • Индексация — доступ к элементам по индексу.
📄 examples/list_characteristics.py
fruits = ["apple", "banana", "cherry"]  # Список строк
numbers = [1, 2, 3]                       # Список чисел
mixed = [42, "Python", 3.14, True, [1, 2, 3]]  # Разные типы

print(fruits)
print(numbers)
print(mixed)

Создание списков

Список создаётся с помощью квадратных скобок []; элементы внутри разделяются запятыми. Пустой список — [] или list().

📄 examples/creating_lists.py
# List literal
my_list = [1, 2, 3, 4]
print(my_list)

# Empty list
empty_1 = []
empty_2 = list()
print(empty_1, empty_2)

# From string
chars = list("python")
print(chars)  # ['p', 'y', 't', 'h', 'o', 'n']

# From range
numbers = list(range(0, 10, 2))
print(numbers)  # [0, 2, 4, 6, 8]

Индексация списков

Индексация списков работает так же, как индексация строк: первый элемент имеет индекс 0, последний — -1. Обращение к несуществующему индексу вызывает IndexError.

📄 examples/list_indexing.py
my_list = ["apple", "banana", "cherry", "date"]

print(my_list[0])   # apple
print(my_list[3])   # date
print(my_list[-1])  # date
print(my_list[-4])  # apple

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

Срез — это способ получить подсписок без изменения исходного списка. Синтаксис: list[start:stop:step]. start включается, stop — не включается. По умолчанию start = 0, stop = len(list), step = 1.

📄 examples/list_slicing.py
my_list = [0, 1, 2, 3, 4, 5, 6]

print(my_list[1:4])    # [1, 2, 3]
print(my_list[::2])    # [0, 2, 4, 6]
print(my_list[::-2])   # [6, 4, 2, 0]
print(my_list[4::-1])  # [4, 3, 2, 1, 0]
print(my_list[3:])     # [3, 4, 5, 6]
print(my_list[:])      # [0, 1, 2, 3, 4, 5, 6] — копия

# Negative indices
print(my_list[-4:-1])      # [3, 4, 5]
print(my_list[-2:-5:-1])   # [5, 4, 3]
print(my_list[::-1])       # [6, 5, 4, 3, 2, 1, 0]

Изменение по индексу и срезу

Элементы списка можно изменять напрямую по индексу. Можно заменить сразу несколько элементов через срез.

📄 examples/list_modifying.py
# Change by index
my_list = ["apple", "banana", "cherry"]
my_list[1] = "blueberry"
print(my_list)  # ['apple', 'blueberry', 'cherry']

# Change by slice
my_list = [10, 20, 30, 40, 50]
my_list[1:3] = [200, 300]
print(my_list)  # [10, 200, 300, 40, 50]

# Negative index
my_list = [100, 200, 300, 400]
my_list[-1] = 500
print(my_list)  # [100, 200, 300, 500]

Операции со списками

Списки поддерживают конкатенацию +, повторение *, проверку вхождения in, получение длины len() и поэлементное сравнение.

📄 examples/list_operations.py
# Concatenation
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = list1 + list2
print(combined)  # [1, 2, 3, 4, 5, 6]

# Repetition
zeros = [0] * 5
print(zeros)  # [0, 0, 0, 0, 0]

repeated = [1, 2, 3] * 2
print(repeated)  # [1, 2, 3, 1, 2, 3]

# Membership
numbers = [1, 2, 3, 4, 5]
print(3 in numbers)   # True
print(6 in numbers)   # False

fruits = ["apple", "banana", "cherry"]
print("apple" in fruits)  # True
print("app" in fruits)    # False — ищет целый элемент

# Length
print(len(numbers))  # 5

Сравнение списков

Списки сравниваются поэлементно: Python идёт слева направо и находит первое отличие. Для корректного сравнения элементы должны быть одного типа или поддерживать сравнение между собой. Если в списках встречаются несравнимые типы, возникает TypeError.

📄 examples/list_comparison.py
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = [1, 3, 0]

print(list1 == list2)  # True
print(list1 == list3)  # False
print(list1 < list3)   # True, потому что 2 < 3

# Comparable types: int and float
print([1, 2.6, 2] < [1, 2, 3])  # False

# Incomparable types
# print([1, 2, "apple"] < [1, 2, 3])  # TypeError
💡 На заметку: при первом отличии сравнение останавливается. Поэтому если после него идут несравнимые типы, ошибки не будет.
📄 examples/list_comparison_stop.py
list1 = [1, 2, "apple"]
list2 = [1, 3, 10]
print(list1 < list2)  # True: 2 < 3, дальше не сравнивается

Цикл for со списками

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

📄 examples/for_over_list.py
my_list = [1, 2, 3, 4, 5]
for item in my_list:
    print(item)

Если нужен и индекс, и значение, удобно использовать enumerate():

📄 examples/enumerate_demo.py
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

# Output:
# 0: apple
# 1: banana
# 2: cherry
Проверить по документации: функция enumerate() выходит за рамки исходного занятия, но является стандартным способом получить индекс в цикле. Подробнее — в разделе Ресурсы.

Вложенные циклы со списками

Если элементы списка сами являются итерируемыми объектами (например, строками), можно использовать вложенные циклы. Внешний цикл перебирает элементы списка, внутренний — символы строки.

📄 examples/nested_loops.py
my_strings = ["apple", "banana", "cherry"]
for word in my_strings:
    for letter in word:
        print(letter, end="")
    print()  # new line after each word

# Output:
# apple
# banana
# cherry

Типизация списков (кратко)

В современном Python можно указывать, какие типы данных хранит список. Это не влияет на выполнение, но помогает редакторам и читателям кода.

📄 examples/list_type_hints.py
from typing import List

names: List[str] = ["Alice", "Bob", "Charlie"]
scores: List[int] = [85, 92, 78]

print(names)
print(scores)
Проверить по документации: аннотации типов (List[str], List[int]) выходят за рамки исходного занятия. Они не обязательны для начинающих, но полезны в реальных проектах.