Оператор в Python — это символ или ключевое слово, которое выполняет операцию над одним или несколькими значениями. Значения, к которым оператор применяется, называются операндами: в выражении 3 + 5 знак + — оператор, а 3 и 5 — операнды. Ниже разбираю семь групп операторов (арифметические, сравнения, логические, битовые, присваивания, членства, тождественности), правила приоритета и главную ловушку новичка — разницу между == и is. Примеры проверены на Python 3.14.
Содержание
Оператор и функция — в чем разница
Термины путают, разведу сразу. Оператор — это встроенный синтаксис языка: a + b, x in seq, p is None. Функция — вызываемый объект: len(seq), abs(a), sum(x).
Граница подвижная: почти каждый оператор внутри вызывает «магический» метод. a + b — это a.__add__(b), a == b — это a.__eq__(b). Поэтому один оператор ведет себя по-разному для разных типов: 1 + 2 дает 3, а "1" + "2" дает "12".
Арифметические операторы
Выполняют математические действия над числами. Начну с полного примера, который можно запустить целиком.
a, b = 17, 5
print(a + b) # 22 сложение
print(a - b) # 12 вычитание
print(a * b) # 85 умножение
print(a / b) # 3.4 деление, всегда float
print(a // b) # 3 целочисленное деление, отбрасывает дробь вниз
print(a % b) # 2 остаток от деления
print(a ** b) # 1419857 возведение в степень
Две тонкости, на которых спотыкаются. Первая: / в Python 3 всегда возвращает float, даже когда деление ровное — 10 / 2 даст 5.0, а не 5. Для целого результата берут //.
Вторая: // и % округляют «вниз» (к минус бесконечности), а не «к нулю». На отрицательных числах это заметно.
print(-17 // 5) # -4, а не -3
print(-17 % 5) # 3, знак совпадает со знаком делителя (5)
Сохраняется тождество a == (a // b) * b + (a % b): подставив, получаем -17 == (-4)*5 + 3.
Операторы сравнения
Сравнивают операнды и возвращают True или False. Их шесть.
| Оператор | Значение | Пример | Результат |
|---|---|---|---|
== |
равно по значению | 5 == 5.0 |
True |
!= |
не равно | 5 != 4 |
True |
> |
больше | 7 > 3 |
True |
< |
меньше | 2 < 1 |
False |
>= |
больше или равно | 5 >= 5 |
True |
<= |
меньше или равно | 4 <= 3 |
False |
Устаревший знак неравенства <> из Python 2 в третьей версии удален — при попытке использовать его будет SyntaxError. Всегда пишут !=.
Особенность Python: сравнения можно связывать в цепочку. Запись 1 < x < 10 означает 1 < x and x < 10, причем x вычисляется один раз.
x = 5
print(1 < x < 10) # True
print(3 == 3 == 3) # True, цепочка работает и для равенства
Логические операторы
Работают с истинностью и возвращают не обязательно bool, а один из операндов. Их три: and, or, not.
print(True and False) # False
print(True or False) # True
print(not True) # False
Важная деталь — «ленивое» вычисление (short-circuit). and останавливается на первом ложном операнде, or — на первом истинном, и возвращают именно этот операнд, а не приведенный к bool результат.
print(0 and 5) # 0 - and вернул первый ложный операнд
print(2 and 5) # 5 - первый истинный, поэтому вернулся второй
print(0 or "def") # def - or вернул первый истинный операнд
Это дает частый идиом — подстановку значения по умолчанию: name = user_input or "гость" присвоит "гость", если user_input — пустая строка. Оговорка: прием ломается, когда допустимое значение само «ложное» (например 0 или ""); тогда берут явную проверку if user_input is None.
Битовые операторы
Работают с числом как с набором двоичных разрядов. Новичку они нужны редко, но пригодятся при работе с флагами, масками и низкоуровневыми протоколами.
| Оператор | Название | Пример (a=6, b=3) |
Результат |
|---|---|---|---|
& |
битовое И | a & b |
2 |
\| |
битовое ИЛИ | a \| b |
7 |
^ |
исключающее ИЛИ | a ^ b |
5 |
~ |
инверсия (унарный) | ~a |
-7 |
<< |
сдвиг влево | a << 1 |
12 |
>> |
сдвиг вправо | a >> 1 |
3 |
Разберу на битах: 6 это 0b110, 3 это 0b011.
a, b = 6, 3
print(bin(a & b)) # 0b10 = 2, единицы там, где они в ОБОИХ
print(bin(a | b)) # 0b111 = 7, единицы там, где хотя бы в одном
print(bin(a ^ b)) # 0b101 = 5, единицы там, где РОВНО в одном
print(a << 1) # 12, сдвиг влево на 1 = умножение на 2
print(a >> 1) # 3, сдвиг вправо на 1 = целочисленное деление на 2
Инверсия ~a дает -7, потому что для целых со знаком выполняется тождество ~a == -a - 1. Это не «ошибка», а следствие представления отрицательных чисел в дополнительном коде.
Операторы присваивания
Записывают значение в переменную. Кроме простого = есть составные формы «операция и присваивание».
| Оператор | Эквивалент | Пример |
|---|---|---|
= |
— | a = 7 |
+= |
a = a + b |
a += 3 |
-= |
a = a - b |
a -= 3 |
*= |
a = a * b |
a *= 3 |
/= |
a = a / b |
a /= 3 |
//= |
a = a // b |
a //= 3 |
%= |
a = a % b |
a %= 3 |
**= |
a = a ** b |
a **= 3 |
&= \|= ^= <<= >>= |
битовые с присваиванием | a <<= 1 |
total = 10
total += 5 # то же, что total = total + 5
print(total) # 15
total //= 4
print(total) # 3
Отдельно стоит «морж» := (walrus, с Python 3.8) — он присваивает и одновременно возвращает значение, что удобно внутри условий: while (line := input()) != "stop":. Обычное = так не умеет — выражением оно не является.
Операторы членства: in и not in
Проверяют, входит ли элемент в последовательность (строку, список, кортеж, множество) или ключ в словарь. Возвращают bool.
letters = "python"
print("t" in letters) # True, подстрока найдена
print("z" in letters) # False
nums = [10, 20, 30]
print(25 not in nums) # True, 25 в списке нет
print(20 in nums) # True
user = {"name": "Ann", "age": 20}
print("name" in user) # True - проверяется КЛЮЧ, не значение
print("Ann" in user) # False - значения так не ищутся
Ключевая оговорка: для словаря in смотрит на ключи. Чтобы искать по значениям, пишут "Ann" in user.values(). Для строки in проверяет вхождение подстроки, а не одного символа: "th" in "python" тоже True.
Операторы тождественности: is и not is
Здесь — самая частая ошибка новичка. == и is спрашивают разное.
==сравнивает значения: «равны ли операнды по содержимому» (через__eq__).isсравнивает идентичность: «это буквально один и тот же объект в памяти» (сравниваетid()).
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True - содержимое совпадает
print(a is b) # False - это два РАЗНЫХ списка
print(a is c) # True - c и a ссылаются на один объект
print(id(a) == id(b)) # False, разные адреса
print(id(a) == id(c)) # True, один адрес
Практическое правило: с None, True, False сравнивают через is, потому что это объекты-одиночки (в интерпретаторе существует ровно по одному экземпляру). Пишут if x is None, а не if x == None — так надежнее и быстрее. Для сравнения по значению (числа, строки, списки) берут ==.
Ловушка кеширования маленьких чисел
Начинающие «проверяют» is на числах и делают неверный вывод. CPython заранее создает объекты для небольших целых (по реализации — диапазон от -5 до 256) и переиспользует их, поэтому два таких числа гарантированно оказываются одним объектом.
x = 256
y = 256
print(x is y) # True - оба ссылаются на один кешированный объект
С числами вне этого диапазона результат становится непредсказуемым и зависит от того, как выполняется код. В интерактивном интерпретаторе каждая строка компилируется отдельно, поэтому два литерала 257 — разные объекты:
>>> x = 257
>>> y = 257
>>> x is y
False
А вот те же три строки внутри одного .py-файла дадут True: при компиляции модуля одинаковые константы в пределах одного блока кода схлопываются в один объект. Один и тот же код в REPL и в скрипте дает разный ответ — вот почему на is тут нельзя полагаться.
Вывод один: это деталь реализации CPython, а не гарантия языка — на другом интерпретаторе или в другом контексте результат другой. Поэтому числа никогда не сравнивают через is, только через ==. is — для идентичности объектов, == — для равенства значений.
Приоритет операторов
Когда в одном выражении несколько операторов, порядок их выполнения задает приоритет — как в математике, где умножение раньше сложения. Ниже группы от высшего приоритета к низшему (полная таблица есть в документации).
| Приоритет | Операторы |
|---|---|
| выше | ** (возведение в степень) |
~ + - (унарные) |
|
* / // % |
|
+ - (бинарные) |
|
<< >> |
|
& затем ^ затем \| |
|
сравнения == != < > <= >=, а также in is |
|
not |
|
and |
|
| ниже | or |
print(2 + 3 * 4) # 14, умножение раньше сложения
print((2 + 3) * 4) # 20, скобки меняют порядок
print(2 ** 3 ** 2) # 512, ** правоассоциативен: 2 ** (3 ** 2)
print(not 1 == 1) # False, сравнение раньше not: not (1 == 1)
Две ловушки приоритета: ** правоассоциативна, поэтому 2 ** 3 ** 2 это 2 ** 9 = 512, а не 64; а унарный минус слабее степени — -3 ** 2 равно -9, потому что читается как -(3 ** 2). Когда порядок неочевиден, ставьте скобки.
Выводы
- Оператор выполняет операцию над операндами; за большинством операторов стоит «магический» метод (
+это__add__,==это__eq__), поэтому поведение зависит от типа. /всегда даетfloat, а//и%округляют вниз — на отрицательных числах результат неинтуитивен, но подчиняется тождествуa == (a//b)*b + a%b.and/orвычисляются лениво и возвращают операнд, а неbool; это удобно для значений по умолчанию, но осторожно с «ложными» допустимыми значениями.==сравнивает значения,is— идентичность объектов; сNoneиспользуютis, числа черезisне сравнивают из-за кеширования маленьких int в CPython.- Приоритет решает порядок вычислений;
**правоассоциативна, унарный минус слабее степени — в спорных местах ставьте скобки.
Где применяется / связь с практикой
Операторы — фундамент любого кода: без них не написать ни условия if age >= 18, ни цикла while count < 10, ни фильтра if item in allowed. Разница == и is, ленивые and/or и приоритет — те места, где ошибки живут молча: код не падает, но считает не то. Поэтому операторы разбирают в самом начале обучения и закрепляют на практике.
Освойте тему на практике
Системно синтаксис, типы данных и работу с выражениями проходят на курсе Python для начинающих — с проверкой домашних заданий и разбором типичных ошибок. Посмотреть формат и уровень занятий можно на открытых уроках Otus — они бесплатные и проходят регулярно.
FAQ
Почему 0.1 + 0.2 == 0.3 дает False?
Это не про операторы, а про формат чисел с плавающей точкой: 0.1 и 0.2 хранятся приближенно, их сумма чуть больше 0.3. Для сравнения дробных используют math.isclose(0.1 + 0.2, 0.3).
Чем and отличается от битового &?
and — логический оператор, работает с истинностью и вычисляется лениво. & — битовый, обрабатывает каждый разряд числа отдельно. 5 and 3 даст 3, а 5 & 3 даст 1. Путать их — частая причина неверных условий.
Можно ли определить свой оператор + для своего класса?
Своих символов операторов добавить нельзя, но поведение существующих переопределяется. Реализуйте метод __add__ в классе — и + начнет работать с его экземплярами так, как вы задали. Это называется перегрузкой операторов.



