in в Python: есть ли элемент в списке
Один оператор вместо цикла с флагом: in задаёт списку вопрос есть ли элемент и отвечает True или False. Разбираем ответ, перевёрнутый not in и коварное сравнение целиком.
Редакция Питоники
Самый частый вопрос к списку звучит не «что лежит на третьем месте», а «есть ли это вообще тут». Был ли товар в корзине, входит ли пользователь в стоп-лист, разрешено ли имя. До знакомства с оператором in такой вопрос решают циклом со счётчиком и условием — пять строк на один вопрос. in делает ту же работу одним выражением. Разберём, как оператор отвечает, как спросить наоборот, где он ищет целиком, а где по частям — и во сколько обходится проверка.
in отвечает True или False
Оператор ставится между искомым значением и списком и возвращает булев ответ — на нём можно сразу печатать и строить условия:
cart = ['молоко', 'хлеб', 'сыр']
print('хлеб' in cart)
print('крупа' in cart)
print(40 in [10, 20, 40])
True False True
Три вопроса — три честных ответа. Оператор in отвечает одним словом: True, если элемент в списке есть, и False, если его там нет. Сам список проверка не меняет: in только спрашивает, а не редактирует. Тип значения не важен — строки и числа список проверяет одинаково.
not in: вопрос наоборот
Обратный вопрос — убедиться, что элемента нет — задаёт оператор not in. Он читается как обычная фраза и избавляет от отрицания результата:
banned = ['spam', 'troll']
user = 'guest'
print(user not in banned)
banned.append(user)
print(user not in banned)
True False
Гость был вне стоп-листа — True; после добавления через append проверка перевернулась. Список вырос на один элемент, и in это сразу заметил: оператор смотрит в актуальное состояние, а не в снимок на момент записи условия.
Старый способ: цикл с флагом
Приём с циклом до сих пор живёт в чужом коде, поэтому полезно узнавать его в лицо: переменная-флаг стартует с False и включается, если совпадение нашлось:
names = ['анна', 'борис', 'вера']
target = 'борис'
found = False
for name in names:
if name == target:
found = True
print(found)
print(target in names)
True True
Ответ один и тот же, но нижняя строка сделала его без флага, без условия и без цикла. Цикл с флагом не ошибочен — он просто пересказывает словами то, что in выражает синтаксисом: сравнить каждый элемент с искомым и сообщить, нашлось ли хоть одно совпадение.
in сравнивает элемент целиком
Тонкое место оператора: у строки in ищет подстроку, а у списка — только целый элемент. Стоит поставить оба случая рядом, и разница становится видимой:
word = 'молоко'
cart = ['молоко', 'хлеб']
print('ло' in word)
print('ло' in cart)
print('молоко' in cart)
True False True
Слово 'ло' внутри строки нашлось — True. Внутри списка такого элемента нет: там лежат 'молоко' и 'хлеб', а куска 'ло' ни один из них не является — False. Список не заглядывает внутрь своих элементов: он сравнивает каждый с искомым целиком, и совпадение должно быть полным.
Тип важен: строка и число не равны
Второй сюрприж подстерегает на данных из ввода и файлов: там всё строки, а в списке могут лежать числа. Python при проверке in типы не приводит:
cart = [5, 10, 15]
print(10 in cart)
print('10' in cart)
print(str(10) in ['10'])
True False True
Число 10 в списке есть, строка '10' — нет: для Python это разные значения, хоть печатаются они одинаково. Если данные пришли строкой, а список хранит числа, проверку нужно готовить заранее — превратить строку в число функцией int или хранить всё в одном типе.
Сколько стоит проверка
Механизм у списка простой: перебор. Чтобы ответить на вопрос, Python по очереди сравнивает элементы с искомым — нашёл на пятой позиции, сделал пять сравнений; не нашёл — прошёл список до конца. На больших данных цена растёт вместе с длиной:
big = list(range(1000000))
print(999999 in big)
print(1234567 in big)
print(len(big))
True False 1000000
Ответы верные, но второй потребовал миллиона сравнений впустую: числа 1234567 в списке нет, и перебор дошёл до конца. Множество на том же вопросе отвечает мгновенно — там поиск устроен через хеш и не зависит от размера. Когда проверок становится много, список стоит превратить во множество — полный разбор скорости в уроке про in у множеств.
in внутри if
Главная работа in — условия. Булев ответ встраивается в if так же естественно, как сравнение чисел:
logins = ['anna', 'boris', 'admin']
if 'admin' in logins:
print('админ на месте')
if 'hacker' not in logins:
print('чужих нет')
админ на месте чужих нет
Обе ветки сработали: админ нашёлся, чужой не нашёлся. Читается такое условие как обычная фраза — «если админ среди логинов» — и именно в таком виде оператор встречается в реальном коде чаще всего.
| Справа стоит | Что проверяет in | Пример |
|---|---|---|
| Список | Целый элемент | 'хлеб' in cart |
| Строка | Подстроку | 'ло' in 'молоко' |
| Словарь | Ключ | 'цена' in goods |
| Множество | Элемент, мгновенно | 'spam' in banned |
goods = {'хлеб': 40, 'молоко': 85}
print('хлеб' in goods)
print(40 in goods)
Проверка принадлежности встала в арсенал: одно выражение вместо цикла с флагом. Следующий шаг — один вызов вместо цикла-счётчика: встроенные min, max и sum считают сумму, минимум и максимум списка одной строкой.
Сначала предскажи ответ в голове — это главный навык программиста.
nums = [4, 8, 15]
print(8 in nums)
print('8' in nums)
print(16 not in nums)
word = 'кот'
words = ['кот', 'код']
print('о' in word)
print('о' in words)
cart = ['чай', 'кофе']
order = 'кекс'
if order not in cart:
cart.append(order)
print(len(cart))
print(order in cart)
1. Что вернёт выражение 'хлеб' in ['молоко', 'хлеб', 'сыр']?
2. Что вернёт 'ло' in ['молоко', 'хлеб']?
3. Что вернёт '10' in [10]?
4. Как убедиться, что элемента в списке нет?
5. Как список отвечает на проверку in внутри?
6. Что напечатает код: banned = ['spam']; banned.append('troll'); print('troll' not in banned)?
Даны логины logins = ['anna', 'boris', 'vera'] и проверяемое имя login = 'boris'. Напечатайте три строки: есть ли login в списке, нет ли его в списке и входит ли фрагмент 'ris' в список логинов.
Что делает оператор in в Python?
Проверяет принадлежность: значение in коллекция возвращает True, если элемент найден, и False, если нет. У списка он сравнивает элементы целиком, у строки ищет подстроку, у словаря проверяет ключи, у множества отвечает мгновенно через хеш. Сама коллекция при проверке не меняется.
Урок 9 раздела Списки: агрегатыКак проверить, что элемента нет в списке?
Оператором not in: if user not in banned вернёт True, когда элемента нет. Писать отрицание вручную (not user in banned) можно, но not in читается естественнее и является стандартным способом.
Почему in не находит часть слова в списке?
Потому что список сравнивает элементы целиком: 'ло' in ['молоко'] — это False, среди элементов нет точного значения 'ло'. Подстроки умеет искать in у самой строки: 'ло' in 'молоко' — True. Чтобы найти элементы, содержащие фрагмент, нужен цикл с проверкой фрагмента внутри каждого элемента.
Поиск в строках: find, rfind и inБыстро ли работает проверка in у списка?
Список отвечает перебором: время растёт вместе с длиной, на миллионе элементов неудачная проверка требует миллиона сравнений. Если проверок много, список стоит превратить во множество: у него in отвечает мгновенно при любом размере.
Урок 5 раздела Множества: мгновенный inПонравился урок? Сошлитесь на него
«Оператор in отвечает одним словом: True, если элемент в списке есть, и False, если его там нет.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Списки · Урок 7
Python срезы списка: [1:4], отрицательные границы и шаг
Срез nums[1:4] берёт элементы с индексами 1, 2 и 3 — правая граница не входит. Опущенные границы, минус-индексы и шаг [::-1] для разворота.
Множества · Урок 5
in в Python: мгновенная проверка принадлежности множеству
Один оператор, два механизма: in у множества отвечает мгновенно, у списка — перебором. Почему на миллионе элементов разница становится днями и секундами.
Словари · Урок 7
in: проверка ключа в словаре
Оператор in отвечает на вопрос «есть ли такой ключ»: проверка перед доступом вместо KeyError, not in, грабли с проверкой значений и причина скорости поиска.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Циклы · Урок 9
else у циклов в Python: поиск без флагов
У циклов for и while есть собственный else: он срабатывает, если перебор дошёл до конца без break. Поиск «нашли или нет» — в один заход и без флагов.
поиск в списке pythonпоиск элемента в цикле
Циклы · Урок 17
Паттерн «первый подходящий»: поиск в цикле Python
Три способа найти первый подходящий элемент: цикл с break, next с генератором и ветка «не нашлось» — с дефолтом вместо падения.
python поиск в циклеpython найти первый элемент в списке
Списки · Урок 4
Python удалить элемент из списка: remove, pop и del
remove убирает по значению, pop снимает элемент и возвращает его, del режет по индексу. Каждый падает по-своему — покажем и обезвредим.
python удалить элемент из спискаdel python список