Узнаем тип числа: int, float, complex
Основные способы проверки типа числа в Python
Python поддерживает три встроенных числовых типа: int (целое), float (вещественное) и complex (комплексное). При работе с данными часто требуется определить, к какому из этих типов относится переменная. Ниже рассмотрены основные методы проверки, их сильные стороны и возможные подводные камни.
Как наиболее эффективно проверить тип числа с учётом наследования?
Лучший способ - функция isinstance(). Она учитывает иерархию классов (например, bool является подклассом int). Пример:
x = 10
print(isinstance(x, int)) # True
print(isinstance(x, float)) # False
print(isinstance(x, (int, float, complex))) # Trueтип числа python (тип числа в python)
Пояснение: isinstance(x, int) вернёт True для целых чисел и для булевых значений (True, False), так как bool унаследован от int. Если нужно проверить принадлежность сразу к нескольким типам, передаётся кортеж типов.
Проблема: isinstance(True, int) даёт True. Это может быть неожиданно, если требуется отличить именно целое число от логического. Решение - дополнительно проверить, не является ли значение булевым: type(x) is not bool and isinstance(x, int).
Как проверить точное соответствие типу без учёта наследования?
Используйте type() и сравнение с типом через is или ==:
x = 3.14
print(type(x) is float) # True
print(type(x) == int) # False
print(type(True) is int) # False (так как type(True) - bool)
Пояснение: type(x) возвращает класс объекта. Сравнение is предпочтительнее, так как он быстрее и гарантирует точное совпадение. Этот метод не считает bool за int.
Проблема: не работает для проверки нескольких типов. Придётся писать type(x) is int or type(x) is float. Альтернатива - type(x) in (int, float, complex).
Как проверить, является ли значение любым числовым типом (включая Decimal, Fraction)?
Модуль numbers содержит абстрактные базовые классы. Например, numbers.Number охватывает все встроенные числовые типы и пользовательские, зарегистрированные как числовые:
import numbers
x = 42
print(isinstance(x, numbers.Number)) # True
print(isinstance(2+3j, numbers.Complex)) # True
print(isinstance(3.14, numbers.Real)) # True
print(isinstance(5, numbers.Integral)) # True
Пояснение: numbers.Number - верхний уровень. Для более точной проверки используйте numbers.Complex, numbers.Real, numbers.Integral. Этот подход полезен, когда код должен работать не только со стандартными типами, но и с Decimal, Fraction и т.д.
Проблема: модуль numbers не входит в ядро языка и может быть неочевиден для новичков. Также isinstance(True, numbers.Integral) вернёт True.
Расширенные примеры проверки типа числа
Ниже приведены дополнительные сценарии и кейсы, которые помогут глубже понять особенности определения числовых типов.
Пример 1: поведение bool при проверке типа
# bool - подкласс int
flag = True
print(type(flag)) # <class 'bool'>
print(isinstance(flag, int)) # True (опасно)
# как отличить?
print(type(flag) is int) # False
print(isinstance(flag, int) and type(flag) is not bool) # False
<class 'bool'> True False False
Пояснение: если требуется исключить булевы значения, нужно явно проверять, что тип не bool.
Пример 2: проверка комплексных чисел
c = 1 + 2j
print(isinstance(c, complex)) # True
print(isinstance(c, numbers.Complex)) # True
print(type(c) is complex) # True
# Но комплексное число не является вещественным
print(isinstance(c, numbers.Real)) # False
True True True False
Пояснение: complex - отдельный тип. Проверка через numbers.Complex полезна для обобщённого кода.
Пример 3: проверка на целое число без плавающей точки (float, представляющий целое)
# float может хранить целые значения, но тип остаётся float
y = 5.0
print(type(y) is float) # True
print(isinstance(y, int)) # False (так как это float)
# метод is_integer() позволяет проверить, является ли float целым числом
print(y.is_integer()) # True
z = 5.5
print(z.is_integer()) # False
True False True False
Пояснение: float.is_integer() возвращает True, если дробная часть равна нулю. Это не проверка типа, но полезно при работе с вещественными числами.
Пример 4: проверка NaN и Infinity
import math
nan = float('nan')
inf = float('inf')
print(type(nan) is float) # True
print(math.isnan(nan)) # True
print(math.isinf(inf)) # True
# isinstance не различает специальные значения
print(isinstance(nan, float)) # True
True True True True
Пояснение: NaN и Infinity - это допустимые значения float, поэтому проверка типа вернёт float, но для их обнаружения нужны специальные функции.
Пример 5: использование numbers.Number для проверки произвольного числа
import numbers
from decimal import Decimal
from fractions import Fraction
d = Decimal('10.5')
f = Fraction(3, 4)
print(isinstance(d, numbers.Number)) # True
print(isinstance(f, numbers.Number)) # True
print(isinstance(d, numbers.Real)) # True (Decimal считается Real)
print(isinstance(f, numbers.Real)) # True
True True True True
Пояснение: абстрактные классы numbers охватывают не только встроенные типы, но и популярные расширения, что делает код более универсальным.
Пример 6: типичные ошибки при проверке типа
# Ошибка: сравнение с строкой вместо типа
x = 10
# Неправильно: if type(x) == "int": # всегда False
# Правильно: if type(x) is int:
# Ошибка: забыть про bool
if isinstance(False, int): # True, хотя False - не число с точки зрения логики
print("bool считается int") # сработает
# Ошибка: путаница между type() и isinstance() при проверке наследования
# type() не учитывает подклассы, isinstance() учитывает.
bool считается int
Пояснение: эти подводные камни часто приводят к багам, особенно при обработке логических флагов вместе с числами.