Выполнение операций над операндами разных типов

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

Смешивание типов — это вещь в Python, которая возникает, когда выражение содержит два или более операнда разных типов. Каким-то образом это выражение должно быть оценено, а для этого необходимо установить точки соприкосновения. Рассмотрим самый простой из случаев, когда задействованы некоторые арифметические операции и пара типов операндов:

# define an integer
a = 3
# define a float number
b = 1.5
# add the two and store it in another variable
c = a + b
print(f"{type(a)}: {a}")
print(f"{type(b)}: {b}")
print(f"{type(c)}: {c}")
Output:
<class 'int'>: 3
<class 'float'>: 1.5
<class 'float'>: 4.5

Что сейчас произошло? Итак, когда мы сложили два числа, целое внутренне преобразовалось в float, затем сложение было выполнено как между двумя числами с плавающей запятой. Как следствие, результат имеет тип float.

Теперь это может быть или не быть лучшим случаем для демонстрации смешивания типов, потому что можно утверждать, что результат сложения не может быть сохранен ни в чем кроме переменной с плавающей запятой, поэтому давайте рассмотрим это следующий:

# define an integer
a = 4
# define a float number
b = 1.5
# multiply the two and store it in another variable
c = a * b
print(f"{type(a)}: {a}")
print(f"{type(b)}: {b}")
print(f"{type(c)}: {c}")
Output:
<class 'int'>: 4
<class 'float'>: 1.5
<class 'float'>: 6.0

На этот раз правило довольно ясное. Целое число было преобразовано в число с плавающей запятой, затем произошло умножение. Тип результата — тип с плавающей запятой, хотя на этот раз он вполне может вписаться в целочисленную переменную. Одно правило становится очень ясным: тип результата идентичен типу самого сложного оператора. В этом случае самый сложный оператор имеет тип float, поэтому результат также будет иметь этот тип.

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

Преобразование выполняется, как я уже упоминал выше, к наиболее сложному типу операнда в выражении по очевидной причине предотвращения потери данных. Представьте, если бы нам пришлось добавить целое число к числу с плавающей запятой:

a = 2
b = 3.7
print(float(a))
print(int(b))
Output:
2.0
3

Добавление a + b в этом случае приведет к 5.7, а результат будет типа float, потому что Python преобразовал целое число a в число с плавающей запятой, что упростило операцию сложения, поскольку оба операнда должны быть совместимы друг с другом и без потерь. данных произошло. Но представьте, если бы Python преобразовывал все операнды не в самый сложный, а в самый простой тип операнда — в нашем случае в целое число. a + b даст нам результат 5. Но мы бы потеряли 0.7 из-за преобразования числа с плавающей запятой в целое число.

Конечно, есть способы переопределить это поведение. Python предлагает несколько удобных функций преобразования типов, таких как int(), float() или complex(). Они используются для преобразования переменных в (или создания) целых, числа с плавающей запятой и комплексных чисел соответственно.

Рассмотрим следующий пример:

a = 2
b = 3.7
c = 4.4
d = a + b + c
e = a + int(b) + int(c)
f = int(a + b + c)
print(f"{type(d)}: {d}")
print(f"{type(e)}: {e}")
print(f"{type(f)}: {f}")
Output:
<class 'float'>: 10.100000000000001
<class 'int'>: 9
<class 'int'>: 10

Сначала мы определили 3 числовые переменные: целое число a и 2 числа с плавающей запятой, b и c.

Затем мы просто сложили их вместе и сохранили результат в d, тип которого, как мы видели, был float, а его значение было 10.1. Это связано с тем, что за кулисами Python преобразовал a в float, а затем выполнил 2.0 + 3.7 + 4.4 и в результате получил 10.1.

Второй тест, который мы сделали, заключался в том, чтобы переопределить неявное преобразование a в float путем явного преобразования b и c в int. Обратите внимание, как преобразование float в int эффективно отбрасывает все, что находится справа от десятичной точки? Вот почему мы получаем только 9, когда суммируем их. 2 + 3 + 4 — это сумма усеченных переменных.

Наконец, третий тест заключался в том, чтобы суммировать их все в соответствии с текущими встроенными правилами преобразования типов только для того, чтобы затем явно преобразовать его в int. Результат неудивительный 10. Все три переменные были выровнены по типу, что означает, что a было неявно преобразовано в float, затем, как видно из первого теста, произошло суммирование: 2.0 + 3.7 + 4.4, в результате получилось значение 10.1, которое стало 10 посредством явного преобразования int() функция.

Другое популярное название, под которым вы найдете явное преобразование, — приведение типов. Итак, вне зависимости от названия, это одно и то же: мы, программисты, используем такие функции, как int(), float() или complex(), для явного преобразования некоторого значения из одного типа в другой. Другими словами, приведение типов выполняется разработчиком, и это также видно в коде. Другими словами, всякий раз, когда мы приводим тип, ответственность за любые потери данных, которые может понести этот процесс приведения типов, ложится на наши плечи.

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

Надо сказать, что не все операторы в Python допускают смешивание типов. Есть ограниченное количество операторов, которые это позволяют. Они разделены на 2 категории:

  • арифметические операторы: +, -, *, /, //, %, **;
  • операторы сравнения: <, >, <=, >=, ==, !=.

Я оставлю вам простой пример смешивания типов с использованием операторов сравнения:

print(2.0 == 2)
Output:
True

Механизм включился и, как всегда, преобразовал целочисленное значение в значение с плавающей запятой, а затем выполнил сравнение между двумя совместимыми значениями, чтобы получить результат True.

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

Дак — инженер-программист, наставник, писатель и иногда даже учитель. Обладая более чем 12-летним опытом разработки программного обеспечения, он теперь является настоящим сторонником языка программирования Python, а его страстью является помощь людям в оттачивании их навыков Python и программирования в целом. Вы можете связаться с колодой в Linkedin, Facebook, Twitter и Discord: Deck451#6188, а также следить за его публикациями здесь, на Medium.