ТЕОРИЯ И ПРАКТИКА

  • Ввод и вывод данных
    • Задачи
  • Условия
    • Задачи
  • Цикл for
    • Задачи
  • Строки
    • Задачи
  • Цикл while
    • Задачи
  • Списки
    • Задачи
  • Двумерные массивы
    • Задачи
  • Словари
    • Задачи
  • Множества
    • Задачи
  • Функции и рекурсия
    • Задачи

Занятие 6. Списки и методы списков в питоне

Введение в списки

Списки в Python: определение и типы данных

Списки (list) — это один из самых универсальных и часто используемых встроенных типов данных в Python. По своей сути, список — это упорядоченная и изменяемая коллекция объектов. В одном списке могут храниться элементы совершенно разных типов.

# Чтобы узнать тип переменной, используется функция type()
my_list = [1, 2, 3]
print(type(my_list))
                        

Основные свойства списков

  • Упорядоченность (Ordered): Элементы в списке хранятся в определённом порядке. У каждого элемента есть свой индекс (порядковый номер), и этот порядок не изменится, если вы его не измените сами.
  • Изменяемость (Mutable): Вы можете изменять список после его создания: добавлять, удалять или изменять его элементы. Это ключевое отличие от кортежей (tuple).

Примеры списков с разными типами данных

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

# Список целых чисел
numbers = [1, 5, -10, 23]

# Список строк
strings = ["hello", "world", "python"]

# Смешанный список: числа, строки, логические значения и даже None
mixed_list = [10, "apple", True, 3.14, None]

print(numbers)
print(strings)
print(mixed_list)
                        

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

Создание пустого списка

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

# Способ 1: с помощью квадратных скобок (наиболее распространённый)
empty_list_1 = []

# Способ 2: с помощью конструктора list()
empty_list_2 = list()

print(f"Пустой список 1: {empty_list_1}")
print(f"Пустой список 2: {empty_list_2}")
                        

Список с элементами одного типа

Чаще всего списки используются для хранения однородных данных.

# Список целых чисел
integer_list = [10, 20, 30, 40, 50]

# Список строк
string_list = ["Москва", "Санкт-Петербург", "Казань"]

print(integer_list)
print(string_list)
                        

Смешанные и вложенные списки

Списки могут содержать другие списки. Такие структуры называются вложенными или двумерными списками и часто используются для представления матриц или таблиц.

# Смешанный список
mixed_data = ["Алексей", 35, "Программист", 185.5, True]

# Вложенный список (матрица 2x3)
matrix = [
    [1, 2, 3],
    [4, 5, 6]
]

print(f"Данные о сотруднике: {mixed_data}")
print(f"Матрица: {matrix}")
# Доступ к элементу вложенного списка: matrix[строка][столбец]
print(f"Элемент в первой строке, втором столбце: {matrix[0][1]}") # Выведет 2
                        

Обращение к элементам списка

Индексация с начала (положительные индексы)

Индексация в Python начинается с 0. Первый элемент имеет индекс 0, второй — 1, и так далее.

fruits = ["apple", "banana", "cherry", "orange"]

# Получаем первый элемент
first_fruit = fruits[0]
print(f"Первый фрукт: {first_fruit}") # 'apple'

# Получаем третий элемент
third_fruit = fruits[2]
print(f"Третий фрукт: {third_fruit}") # 'cherry'
                        

Индексация с конца (отрицательные индексы)

Отрицательная индексация позволяет обращаться к элементам с конца списка. -1 — это последний элемент, -2 — предпоследний и т.д.

fruits = ["apple", "banana", "cherry", "orange"]

# Получаем последний элемент
last_fruit = fruits[-1]
print(f"Последний фрукт: {last_fruit}") # 'orange'

# Получаем предпоследний элемент
second_to_last_fruit = fruits[-2]
print(f"Предпоследний фрукт: {second_to_last_fruit}") # 'cherry'
                        

Срезы (Slices)

Срезы — это мощный инструмент для получения части списка. Они создают новый список, не изменяя исходный.

Основной синтаксис: list[start:stop:step]

  • start: индекс, с которого начинается срез (включительно). Если опущен, срез начинается с 0.
  • stop: индекс, на котором заканчивается срез (не включительно!). Если опущен, срез идёт до конца списка.
  • step: шаг, с которым извлекаются элементы. Если опущен, шаг равен 1.
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Срез со 2-го по 5-й элемент (индексы с 1 по 4)
subset = numbers[1:5]
print(f"Срез с 1 по 4 индекс: {subset}") # [1, 2, 3, 4]

# Срез от начала до 4-го элемента (индекс 3)
first_part = numbers[:4]
print(f"Срез от начала до индекса 3: {first_part}") # [0, 1, 2, 3]

# Срез с 5-го элемента (индекс 4) до конца
last_part = numbers[4:]
print(f"Срез от индекса 4 до конца: {last_part}") # [4, 5, 6, 7, 8, 9]

# Получение каждого второго элемента
every_second = numbers[::2]
print(f"Каждый второй элемент: {every_second}") # [0, 2, 4, 6, 8]

# Переворот списка с помощью среза (шаг -1)
reversed_list = numbers[::-1]
print(f"Перевернутый список: {reversed_list}") # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
                        

Изменение элементов списка

Присваивание значения по индексу

Так как списки изменяемы, вы можете легко заменить один или несколько элементов.

colors = ["red", "green", "blue"]
print(f"Исходный список: {colors}")

# Изменяем второй элемент (индекс 1)
colors[1] = "yellow"
print(f"После изменения одного элемента: {colors}")

# Можно изменять и целый срез
colors[0:2] = ["orange", "purple"]
print(f"После изменения среза: {colors}")
                        

Добавление элементов в список

Метод append()

Добавляет один элемент в самый конец списка.

numbers = [1, 2, 3]
print(f"До append: {numbers}")

numbers.append(4)
print(f"После append(4): {numbers}")
                        

Метод insert()

Вставляет элемент на указанную позицию (индекс).

letters = ['a', 'c', 'd']
print(f"До insert: {letters}")

# Вставляем 'b' на позицию с индексом 1
letters.insert(1, 'b')
print(f"После insert(1, 'b'): {letters}")
                        

Метод extend()

Расширяет список, добавляя в конец все элементы из другой последовательности (например, другого списка).

list1 = [1, 2, 3]
list2 = [4, 5, 6]
print(f"До extend: list1 = {list1}")

list1.extend(list2)
print(f"После extend(list2): list1 = {list1}")

# Сравните с append:
list3 = [1, 2, 3]
list3.append(list2) # append добавит list2 как один вложенный элемент
print(f"Результат с append: {list3}") # [1, 2, 3, [4, 5, 6]]
                        

Удаление элементов из списка

Метод remove()

Удаляет первое найденное вхождение указанного значения. Если значение не найдено, вызывает ошибку ValueError.

pets = ["cat", "dog", "hamster", "dog"]
print(f"До remove: {pets}")

pets.remove("dog") # Удалит первое вхождение "dog"
print(f"После remove('dog'): {pets}")
                        

Метод pop()

Удаляет элемент по указанному индексу и возвращает его. Если индекс не указан, удаляет и возвращает последний элемент.

items = ["book", "pen", "laptop", "mouse"]
print(f"До pop: {items}")

# Удаляем элемент с индексом 1 и сохраняем его
removed_item = items.pop(1)
print(f"Удаленный элемент: {removed_item}")
print(f"После pop(1): {items}")

# Удаляем последний элемент
last_item = items.pop()
print(f"Удаленный последний элемент: {last_item}")
print(f"После pop(): {items}")
                        

Метод clear()

Удаляет все элементы из списка, делая его пустым.

data = [1, 2, 3, 4, 5]
print(f"До clear: {data}")

data.clear()
print(f"После clear: {data}")
                        

Поиск элементов в списке

Метод index()

Возвращает индекс первого вхождения указанного значения. Если значение не найдено, вызывает ошибку ValueError.

numbers = [10, 20, 30, 40, 20, 50]

# Находим индекс первого вхождения числа 30
idx = numbers.index(30)
print(f"Индекс числа 30: {idx}") # 2

# Можно указать начальный индекс для поиска
idx_after_3 = numbers.index(20, 3) # Искать 20, начиная с индекса 3
print(f"Индекс числа 20 после 3-й позиции: {idx_after_3}") # 4
                        

Метод count()

Подсчитывает, сколько раз указанное значение встречается в списке.

grades = ['A', 'B', 'A', 'C', 'A', 'B']

# Считаем количество оценок 'A'
count_a = grades.count('A')
print(f"Количество оценок 'A': {count_a}") # 3
                        

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

Метод sort()

Сортирует список на месте, то есть изменяет исходный список. Ничего не возвращает.

numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print(f"Исходный список: {numbers}")

numbers.sort()
print(f"Отсортированный список: {numbers}")
                        

Функция sorted()

Возвращает новый отсортированный список, оставляя исходный без изменений.

numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print(f"Исходный список: {numbers}")

sorted_numbers = sorted(numbers)
print(f"Новый отсортированный список: {sorted_numbers}")
print(f"Исходный список остался неизменным: {numbers}")
                        

Сортировка в обратном порядке

Оба метода, sort() и sorted(), принимают необязательный аргумент reverse=True.

numbers = [3, 1, 4, 1, 5, 9, 2, 6]

# Сортировка на месте в обратном порядке
numbers.sort(reverse=True)
print(f"Сортировка sort(reverse=True): {numbers}")

# Создание нового списка, отсортированного в обратном порядке
new_sorted_desc = sorted([10, 50, 20], reverse=True)
print(f"Сортировка sorted(reverse=True): {new_sorted_desc}")
                        

Обращение элементов списка

Метод reverse()

Переворачивает порядок элементов в списке на месте.

letters = ['a', 'b', 'c', 'd']
print(f"До reverse: {letters}")

letters.reverse()
print(f"После reverse: {letters}")
                        

Функция reversed()

Возвращает итератор, который проходит по списку в обратном порядке. Исходный список не меняется. Чтобы получить список, результат нужно обернуть в list().

letters = ['a', 'b', 'c', 'd']
print(f"Исходный список: {letters}")

reversed_iterator = reversed(letters)
reversed_list = list(reversed_iterator)

print(f"Новый перевернутый список: {reversed_list}")
print(f"Исходный список не изменился: {letters}")

# Как вы помните, это можно сделать и срезом
reversed_by_slice = letters[::-1]
print(f"Перевернутый список через срез: {reversed_by_slice}")
                        

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

Поверхностное копирование через срезы

Присваивание new_list = old_list не создает копию, а лишь новую ссылку на тот же объект. Чтобы создать независимую копию, можно использовать срез [:].

original_list = [1, 2, 3]

# Неправильное копирование (просто ссылка)
ref_list = original_list
ref_list[0] = 99
print(f"Изменили ref_list, а original_list тоже изменился: {original_list}") # [99, 2, 3]

# Правильное копирование через срез
original_list = [1, 2, 3] # Вернем исходное значение
copied_list = original_list[:]
copied_list[0] = 55
print(f"Изменили copied_list: {copied_list}") # [55, 2, 3]
print(f"original_list при этом не изменился: {original_list}") # [1, 2, 3]
                        

Метод copy()

Метод copy() делает то же самое, что и срез [:] — создает поверхностную копию списка.

original_list = [10, 20, 30]

# Копирование с помощью метода copy()
copied_list = original_list.copy()
copied_list[0] = 111

print(f"Изменили копию: {copied_list}")
print(f"Оригинал не изменился: {original_list}")
                        

Таблица основных методов списков

Методы массивов в питоне

Метод Описание Пример кода Что возвращает?
append(x) Добавляет элемент x в самый конец списка. a = [1, 2]
a.append(3)
print(a) # -> [1, 2, 3]
None
extend(iterable) Расширяет список, добавляя в конец все элементы из переданного итерируемого объекта (например, другого списка). a = [1, 2]
b = [3, 4]
a.extend(b)
print(a) # -> [1, 2, 3, 4]
None
insert(i, x) Вставляет элемент x на позицию с индексом i. a = [1, 3]
a.insert(1, 2)
print(a) # -> [1, 2, 3]
None
remove(x) Удаляет первое найденное в списке значение x. Если такого элемента нет, вызывает ошибку ValueError. a = [1, 2, 3, 2]
a.remove(2)
print(a) # -> [1, 3, 2]
None
pop([i]) Удаляет элемент на позиции i и возвращает его. Если индекс i не указан, удаляет и возвращает последний элемент. a = [1, 2, 3]
x = a.pop(1)
print(a, x) # -> [1, 3] 2
Удаленный элемент
clear() Очищает список, удаляя из него все элементы. a = [1, 2, 3]
a.clear()
print(a) # -> []
None
index(x[, start[, end]]) Возвращает индекс первого вхождения элемента x. Можно ограничить поиск срезом [start:end]. a = ['a', 'b', 'c']
i = a.index('b')
print(i) # -> 1
Индекс элемента (число)
count(x) Возвращает количество вхождений элемента x в списке. a = [1, 2, 3, 2]
c = a.count(2)
print(c) # -> 2
Количество вхождений (число)
sort(key=None, reverse=False) Сортирует элементы списка на месте (in-place). key - функция для вычисления ключа, reverse=True для сортировки по убыванию. a = [3, 1, 2]
a.sort()
print(a) # -> [1, 2, 3]
None
reverse() Разворачивает порядок элементов в списке на месте (in-place). a = [1, 2, 3]
a.reverse()
print(a) # -> [3, 2, 1]
None
copy() Создает и возвращает поверхностную копию списка. Эквивалентно срезу [:]. a = [1, 2]
b = a.copy()
b.append(3)
print(a, b) # -> [1, 2] [1, 2, 3]
Новый список (копия)

Важный момент: многие методы, такие как sort(), reverse(), append() и другие, изменяют список "на месте" (in-place) и возвращают None. Это частая причина ошибок у начинающих, которые пытаются присвоить результат такой операции другой переменной.

Особенности работы со списками разных типов

Списки строк и работа с join

Метод строк .join() позволяет объединить элементы списка строк в одну строку с указанным разделителем.

words = ["Python", "is", "awesome"]

# Объединяем слова через пробел
sentence = " ".join(words)
print(sentence) # "Python is awesome"

# Объединяем через запятую
csv_string = ",".join(words)
print(csv_string) # "Python,is,awesome"
                        

Списки чисел и операции над ними

Со списками чисел удобно работать с помощью встроенных функций и генераторов.

numbers = [1, 2, 3, 4, 5]

# Получение нового списка с квадратами чисел (см. раздел про генераторы)
squares = [x * x for x in numbers]
print(f"Квадраты чисел: {squares}")
                        

Списки логических значений и функции all(), any()

  • all(list) возвращает True, если все элементы списка истинны.
  • any(list) возвращает True, если хотя бы один элемент списка истинен.
bool_list_1 = [True, True, True]
bool_list_2 = [True, False, True]
bool_list_3 = [False, False, False]

print(f"all(bool_list_1): {all(bool_list_1)}") # True
print(f"all(bool_list_2): {all(bool_list_2)}") # False

print(f"any(bool_list_2): {any(bool_list_2)}") # True
print(f"any(bool_list_3): {any(bool_list_3)}") # False
                        

Двумерные списки и их обход

Для обхода двумерных списков (матриц) используются вложенные циклы.

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

# Проход по матрице и печать каждого элемента
for row in matrix: # Сначала итерируемся по строкам
    for element in row: # Затем по элементам в каждой строке
        print(element, end=" ")
    print() # Переход на новую строку после каждой строки матрицы
                        

Итерация по спискам

Простой перебор элементов

Самый частый способ — цикл for.

colors = ["red", "green", "blue"]

for color in colors:
    print(f"Текущий цвет: {color}")
                        

Перебор с использованием enumerate()

Когда нужен не только элемент, но и его индекс, используйте enumerate().

colors = ["red", "green", "blue"]

for index, color in enumerate(colors):
    print(f"Элемент с индексом {index}: {color}")
                        

Генераторы списков (List Comprehensions)

Это элегантный и "питонический" способ создавать списки на основе других последовательностей.

Простейшие генераторы

Синтаксис: [выражение for элемент in последовательность]

# Создание списка чисел от 0 до 9
numbers = [i for i in range(10)]
print(numbers) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Создание списка квадратов
squares = [x**2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
                        

Генераторы с условием (фильтрацией)

Синтаксис: [выражение for элемент in последовательность if условие]

# Создать список только четных чисел от 0 до 10
even_numbers = [x for x in range(11) if x % 2 == 0]
print(even_numbers) # [0, 2, 4, 6, 8, 10]

# Создать список длин строк, которые длиннее 3 символов
words = ["apple", "cat", "window", "dog"]
long_word_lengths = [len(word) for word in words if len(word) > 3]
print(long_word_lengths) # [5, 6]
                        

Встроенные функции для работы со списками

функция len() — длина списка

my_list = [10, 20, 30]
print(len(my_list)) # 3
                        

функция sum() — сумма элементов

Работает только для списков, содержащих числа.

numbers = [1, 2, 3, 4, 5]
print(sum(numbers)) # 15
                        

функция max() и min()

Находят максимальный и минимальный элементы в списке.

numbers = [10, 5, 100, -2]
print(f"Максимум: {max(numbers)}") # 100
print(f"Минимум: {min(numbers)}") # -2
                        

функция zip()

Объединяет несколько списков в один, создавая пары (кортежи) из элементов с одинаковыми индексами.

names = ["Анна", "Борис", "Виктор"]
ages = [25, 30, 35]

zipped_data = zip(names, ages)
print(list(zipped_data)) # [('Анна', 25), ('Борис', 30), ('Виктор', 35)]
                        

функция map()

Применяет функцию к каждому элементу списка. Возвращает итератор.

numbers = [1, 2, 3, 4]

# Применить функцию str ко всем элементам, чтобы превратить их в строки
string_numbers = map(str, numbers)
print(list(string_numbers)) # ['1', '2', '3', '4']
                        

функция filter()

Фильтрует список, оставляя только те элементы, для которых функция-условие возвращает True.

def is_positive(n):
    return n > 0

numbers = [-10, 5, 0, -2, 8]
positive_numbers = filter(is_positive, numbers)
print(list(positive_numbers)) # [5, 8]
                        

Дополнительные задачи и примеры

Поворот списка (сдвиг элементов)

Задача: сдвинуть список [1, 2, 3, 4, 5] на 2 элемента влево, чтобы получилось [3, 4, 5, 1, 2].

Решение через срезы

Это самый простой и элегантный способ.

my_list = [1, 2, 3, 4, 5]
shift = 2

# Соединяем срез, начиная со сдвига, со срезом до сдвига
rotated_list = my_list[shift:] + my_list[:shift]
print(rotated_list) # [3, 4, 5, 1, 2]
                        

Удаление дубликатов с помощью множества (set)

Множества (set) в Python не могут содержать дубликатов. Преобразовав список в множество и обратно, можно легко удалить все повторы. Порядок элементов при этом может не сохраниться.

numbers_with_duplicates = [1, 2, 3, 2, 4, 1, 5, 5]

# Преобразуем в множество, чтобы удалить дубликаты, и обратно в список
unique_numbers = list(set(numbers_with_duplicates))
print(unique_numbers) # [1, 2, 3, 4, 5] (порядок может быть другим)
                        

Разделение списка на части (чанки)

Задача: разделить список [1, 2, 3, 4, 5, 6, 7, 8] на чанки размером 3.

long_list = [1, 2, 3, 4, 5, 6, 7, 8]
chunk_size = 3

# Используем генератор и срезы
chunks = [long_list[i:i + chunk_size] for i in range(0, len(long_list), chunk_size)]
print(chunks) # [[1, 2, 3], [4, 5, 6], [7, 8]]
                        

Преобразование списка списков в плоский список

Задача: превратить [[1, 2], [3, 4], [5]] в [1, 2, 3, 4, 5].

nested_list = [[1, 2], [3, 4], [5]]

# Используем вложенный генератор списков
flat_list = [item for sublist in nested_list for item in sublist]
print(flat_list) # [1, 2, 3, 4, 5]