logo
Ещё

Списки в Python

Список – это базовая структура данных в Python. Вы будете использовать списки очень часто и по самым разным причинам: хранение информации, передача данных куда-либо, сортировка данных и так далее. Кроме того, вы часто будете использовать списки, даже не зная, что вы их использовали, потому что строки – это измененный вариант списков. Поэтому вам нужно знать об этой структуре данных все: как они создаются, как их изменять, какие операторы поддерживаются списками, какие функции языка доступны спискам и какие встроенные функции у списков есть. Обо всем этом – ниже.

Что такое списки

Начнем не со списков в Питоне, а со структур данных как таковых. Если вы работаете с набором данных одного типа, зачастую бывает удобно поместить все эти данные в какое-то одно место, из которого вы будете иметь доступ сразу ко всем этим данным. Таким «местом» во многих языках программирования выступает массив:


Концепция у массивов – очень простая: если для отдельной переменной мы выделяли в памяти, например, 4 байта (стандартный int во многих языках), то для массива мы выделяем те же 4 байта, умноженные на количество элементов массива. Каждому элементу мы назначаем индекс от 0: 0, 1, 2, 3… Почему от 0? Долгая история, если хотите, то можете почитать статью-расследование на Хабре. Важно то, что мы по итогу:

  1. Имеем последовательность элементов одного типа.
  2. Имеем доступ к каждому элементу по его индексу.
  3. Должны заранее выделить место для всего массива, то есть – знать, сколько элементов в нем будет.

Эти свойства массива вы можете увидеть в языках, в которых обычно встречается доступ к адресам и строгая типизация – C или Golang, например. И эти свойства обеспечивают высокую скорость работы массивов, одновременно с этим добавляя проблем в разработке. Основных проблем – 2:

  1. Элементы должны быть одного типа. Допустим, вы создаете приложение, которое принимает от клиента набор данных и что-то с ними делает. При этом клиентское приложение может посылать разные типы данных: целые числа, дробные числа, отдельные символы, строки и структуры. В языках со строгой типизацией вам нужно что-то с этим делать – принимать отдельно каждый элемент (что само по себе – боль, если вы принимаете битовый поток), определять его тип, хранить в отдельном массиве/переменной и создавать какие-то дополнительные указатели, чтобы можно было связать между собой разные данные.
  2. Нужно заранее выделить место для всего массива. Размер массива не может быть изменен, то есть вам нужно брать место «с запасом» и что-то делать в том случае, если лимит массива исчерпан.

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

Python решает обе проблемы: обычных массивов в языке нет вообще, есть списки. Список в Python – это динамический массив, который позволяет хранить в себе данные любых типов. «Под капотом» у списка в Python лежит все тот же массив, но – с динамическим расширением: когда вы добавляете новый элемент в массив, лимит которого исчерпан, Python автоматически создает новый массив увеличенного объема и копирует в него все данные из старого массива. Проблему элементов разных типов Python тоже решает без вашего участия – в массиве хранятся не значения, а указатели на значения, поэтому длина значения в байтах не является проблемой: само значение хранится где-то в куче (специальная «безразмерная» область памяти), в массиве же хранится указатель длиной в (обычно) 4 байта. Но вы должны понимать, что обе эти оптимизации, упрощающие вашу жизнь, уменьшают скорость работы списков в Python.

Вот как выглядит список в Python:


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

  • Все списки упорядочены – индексация элементов начинается с нуля, каждый последующий индекс – больше предыдущего на 1 (в отличие от множеств и словарей).
  • Данные в списках можно менять без ограничений (в отличие от кортежей и, частично, словарей).
  • В списках могут попадаться одинаковые данные (в отличие от множеств).
  • Доступ к элементу списка можно получить по обращению к его индексу в квадратных скобках – testList[0].
  • Списки могут хранить любые типы данных, включая другие списки.

Как создать список в Python – разберем пошагово

Скобки []

Списки создаются либо через встроенную конструкцию, либо через функцию list(). Начнем со встроенной конструкции – квадратных скобок. Создание пустого списка:

testList = []

Создание списка со значениями:

testList = [1, False, “sravni.ru”]

Если вам нужно много одинаковых элементов в списке, вы можете использовать операцию умножения:

testList = [42] * 5


А теперь к сложному – списочные выражения. Python позволяет вставить в инициализацию списка специальное выражение, состоящее из цикла for и, при необходимости, условия if. Форма записи: testList = [выражение цикл (условие)]. Возьмем самое простое:

testList = [x*2 for x in range(5)]


Что тут произошло? Мы создали объект range, который последовательно возвращает числа от 0 до 4, и каждое из этих чисел обрабатывается согласно выражению «x*2», то есть умножается на 2. Мы можем добавить условие:

testList = [x for x in range(10) if x // 2 == 0]


Мы добавили в список только те элементы, которые делятся на 2 без остатка – то есть являются четными. Если в списочное выражение добавить 2 цикла for – вы получите матрицу. Списочные выражения – очень мощный инструмент создания списков, но и очень сложный, поэтому ниже мы его рассматривать не будем – дальнейший разбор выходит за рамки этого материала.

Функция list()

Второй способ создания списков – с помощью встроенной функции list(). Создание пустого списка:

testList = list()

Функция может принимать итерируемый объект (iterable, то, что можно пересчитать) и создавать список на его основе. В этом list() уже сильно отличается от []: если мы, например, передадим строку «Hello, sravni.ru!» в [], то получим список с одним элементом-строкой; если мы передадим его в list(), то получим список, в котором каждый элемент будет отдельным символом строки:


Второй важный момент функции list() – она позволяет копировать список. В примере мы сначала создали список с помощью [], затем через «=» создали второй такой же список. Затем мы изменили элемент во втором списке, вывели первый – и оказалось, что в первом списке элемент тоже поменялся, хотя мы меняли его во втором. Далее мы создали список через list(), на его основе создали такой же дубликат, изменили во втором списке элемент – а в первом ничего не поменялось.


Почему так? Когда мы написали «listWithBracers2 = listWithBracers1», мы на самом деле копировали не список, а указатель на список – то есть у нас возникла вторая переменная, с помощью которой можно было получить доступ к тому же списку. Мы этим доступом воспользовались, поменяли значение – и когда мы запросили вывод через первую переменную, мы получили измененный список. С list() так не работает – мы создаем не указатель, а полностью новый список.

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

Самая базовая операция – это индексация. Получить доступ к элементу списка можно по его индексу: testList[0]. Python поддерживает отрицательную индексацию – в этом случае отсчет начинается с конца:


Для того, чтобы изменить элемент списка, нужно обратиться к конкретному элементу и присвоить этому элементу новое значение. Можно изменять элементы массово – для этого нужно указать срез, который изменяется, и задать ему новые значения, длина среза может отличаться от длины нового подсписка (о срезах поговорим ниже):


По операторам:

  • +: конкатенация (объединение) списков.
  • *: повторить список несколько раз.
  • +=, *=: то же, что и для переменных.
  • in, not in: проверка на присутствие/отсутствие элемента в списке.
  • ==: сравнение, отдает True, если списки полностью аналогичны по длине и содержанию, и False в остальных случаях.


К слову, списки поддерживают и операторы сравнения «>»/«<», но работают они немного контр-интуитивно: Python сравнивает элементы с одинаковыми индексами в каждом списке, и как только по какому-то индексу Питон находит элемент больше/меньше – он возвращает True или False в зависимости от оператора (отсутствие значения по индексу считается самым маленьким значением из возможных):


Логика – запутанная, поэтому ей пользуются нечасто.

Что касается других интересных операций со списками – можно отметить:

  • Итерацию в for. Списки поддерживают конструкцию «for x in list:», такая конструкция последовательно переберет все элементы списка.

  • Распаковку. В различных источниках ее часто называют «разложением списка». Суть – в том, что вы превращаете список в набор отдельных элементов, которые затем куда-то передаете. Распаковка часто используется для передачи аргументов функции.

Работа со встроенными функциями

Многие изучающие Python часто путаются между встроенными функциями и методами списков – например, для списка list1 нужно писать reversed(list1), но list1.reverse(). Внесем ясность:

  • Встроенные функции языка. Это – функции, которые «вшиты» в Python и существуют независимо от типов данных. Выглядят как обычный вызов функции, например – reversed(). Обычно встроенная функция может принимать несколько разных типов данных – тот же reversed() принимает не только списки, но и строки, например.
  • Методы списков. Любой тип данных в Python – это объект, а у объектов часто есть методы – то есть функции, «привязанные» к классу (и, соответственно, объекту класса). У списков тоже есть методы, они вызываются через «.» в формате «объект.метод()»: listreverse().

Встроенных функций в Python – много, полный список вы можете посмотреть вот здесь. Из самого «ходового» для списков:

  • filter(func, list). Первый параметр – функция, которая дает логику фильтрации; второй параметр – список. Возвращает итератор отфильтрованного списка – можно сделать списком через list().
  • isinstance(value, type). Возвращает True, если переменная value имеет тип type. Например: isinstance(testList, list).
  • len(list). Возвращает длину списка.
  • max(list). Возвращает самое большое значение в списке.
  • min(list). Возвращает самое маленькое значение в списке.
  • print(list). Выводит список в стандартный поток вывода.
  • reversed(list). Возвращает итератор перевернутого списка – можно сделать списком через list().
  • sorted(list, key, reverse). Первый параметр – список; второй (опционально) – функция для сортировки; третий (опционально) – флаг сортировки в обратном порядке. Возвращает отсортированный список.
  • str(list). Конвертирует список в строку и возвращает ее.
  • sum(list). Возвращает сумму всех значений списка.

Заметьте, что все эти функции возвращают значение – то есть вам нужно присвоить результат в переменную или передать его куда-либо, чтобы не потерять:


Методы cписков

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

  • .append(element). Добавить элемент к списку, элемент может иметь любой тип.
  • .clear(). Удалить все элементы из списка.
  • .copy(). Копирует список, для которого был вызван метод. Как и в случае со встроенными функциями – результат работы функции нужно чему-то присвоить, например: «list2 = listcopy()».
  • .count(value). Возвращает число, указывающее, сколько раз значение value встречалось в списке.
  • .extend(iterable). Добавляет к списку все значения из iterable.
  • .index(element). Возвращает первое вхождение element в списке, если элемента нет – генерирует ошибку.
  • .insert(position, element). Вставляет элемент в конкретную позицию, все элементы правее сдвигаются на 1.
  • .pop(position). Удаляет элемент по индексу position и возвращает его. Если вызывается без аргументов – удаляет и возвращает последний элемент.
  • .remove(element). Проходится по всему списку и удаляет первый встреченный element.
  • .reverse(). Переворачивает список.
  • .sort(reverse, key). Аргументы – опциональные, первый указывает на сортировку по убыванию, второй позволяет передать функцию для сортировки. Сортирует список.

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

Срез – это список, представляющий собой часть другого списка. В Python срезы создаются с помощью специального синтаксиса: slice = list[start:end:step], где:

  • slice – срез.
  • list – изначальный список.
  • start, end – первый (включая) и последний (не включая) индексы изначального списка.
  • step – шаг.

Индексы могут быть отрицательными – в этом случае они считаются с конца. Шаг тоже может быть отрицательным – тогда слайс будет создаваться от последнего элемента к первому (но нужно указать последний элемент в качестве start и первый в качестве end, иначе получим пустой срез). Start, end и step можно опускать, тогда будут использоваться стандартные значения: индекс 0 для start, индекс последнего элемента + 1 для end, 1 для step.


Строки, словари, множества и кортежи

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

  • Строка. Тип данных для работы с текстом. Поддерживает большинство методов, которые есть у списка. Строки не могут быть модифицированы – если вам нужно удалить символ из строки, то вам нужно создать новую строку без этого символа.
  • Словарь. Тип данных для хранения пар «ключ:значение». Ключ может быть любым, а вот значением может быть только тот тип, который нельзя модифицировать. Кроме того – значения в словарях не упорядочены.
  • Множество. Неупорядоченный набор уникальных данных – значения в множествах не могут повторяться. У множеств – ограниченная сфера применения, но работают они очень быстро.
  • Кортеж. Этот тип данных крайне похож на список, но есть важное отличие: данные в кортеже нельзя менять. Кортежи часто используются как временные хранилища набора данных.

Где учить Python – курсы на Сравни

Каких-то специализированных курсов по спискам нет: списки – это один из базовых инструментов языка, и вам нужно учить весь язык, а не просто списки. Если хотите учиться с ментором и гарантией трудоустройства – присмотритесь к курсам:

  • «Python-разработчик» от Skillbox. Длительность – 10 месяцев.
  • «IT-специалист с нуля» от Skillfactory. Длительность – 18 месяцев.
  • «Python-разработчик» от Академии Синергия. Длительность – 6 месяцев.
  • «Python-разработчик с нуля» от Нетологии. Длительность – 6 месяцев.
  • «Fullstack-разработчик на Python» от Академии Eduson. Длительность – 9 месяцев.

Что еще почитать и посмотреть по теме

Вывод

Тезисно:

  • Список в Python – это структура данных, которая позволяет хранить в себе любое количество элементов любого типа.
  • Списки в Питоне похожи на динамические массивы в других языках.
  • Создавать списки можно как через [], так и через функцию list().
  • Списки работают с рядом операторов: +, *, in, not in, ==. Они также работают с < и >, но поведение – не самое очевидное, поэтому сравнением списков пользуются редко.
  • Многие встроенные функции языка принимают списки (как и любые другие iterable). Кроме того, у списков есть собственные встроенные методы.