Pythonic isinstance для чисел с плавающей запятой и целых чисел

Скажем, у вас есть функция:

def divide(a, b):
    return a / b

Это, очевидно, даст другой результат, если a и b равны float, int или их комбинации. Если вас волнует только ситуация, когда a и b являются числами с плавающей запятой, как лучше всего с этим справиться?

i)

def divide(a, b):
    if not isinstance(a, float):
        raise TypeError('a must be a float')
    if not isinstance(b, float):
        raise TypeError('b must be a float')
    return a / b

ii)

def divide(a, b):
    return float(a) / float(b)

в) что-то еще?

Я предпочитаю ii), но коллега утверждает, что если вы используете a и b в другом месте, то i) с большей вероятностью предотвратит ошибки.

Это, очевидно, несколько тривиальный пример, но у моего коллеги гораздо больше опыта работы с C, и я изо всех сил пытаюсь объяснить, почему использование isinstance на самом деле не подходит для утиного ввода и что его проникновение в наш код Python не очень хорошо.


person BrT    schedule 11.09.2013    source источник
comment
Вам нужно только преобразовать один из операндов: return float(a) / b   -  person martineau    schedule 11.09.2013


Ответы (4)


Другой вариант может быть

def divide(a, b):
    return a * 1.0 / b

or

from __future__ import division

def divide(a, b):
    return a / b
person glglgl    schedule 11.09.2013
comment
Второй вариант — лучший способ решения этой проблемы, поскольку он согласован и рассчитан на будущее. - person Fred Foo; 11.09.2013
comment
@glglgl Я думаю, что ОП спрашивал о «принуждении» к тому, чтобы функция принимала только определенные типы параметров. Он просто использует разделение в качестве примера. - person HennyH; 11.09.2013

Если вы хотите выполнить истинное деление независимо от версии Python и не хотите использовать импорт в будущем, альтернативой является:

from operator import truediv
print truediv(4, 2)
# 2.0

Который всегда будет выполнять истинное деление и возвращать число с плавающей запятой независимо от его ввода (с учетом int/float)... Передача дробей/комплексов/десятичных чисел будет иметь другой результат!

person Jon Clements♦    schedule 11.09.2013

Почему бы не использовать:

def divide(a, b):
    return float(a) / float(b)

Вероятно, одного преобразования в число с плавающей запятой также будет достаточно.

person Michel Keijzers    schedule 11.09.2013

Я предполагаю, что divide() — это всего лишь пример функции, которая может молча выдавать неверный результат, учитывая аргументы с неожиданными типами.

Чтобы избежать жесткого кодирования проверки типа в функции, можно использовать общую функцию, например, get_items() function позволяет обрабатывать оба объекта json и массив json единообразно (сравните реализации convert_decimal(): с isinstance() вызовами и другой с общим get_items()).

Если диспетчеризации, основанной только на типе первого аргумента, недостаточно; см. Мультиметоды за пять минут в Python автора Гвидо ван ван Россум.

person jfs    schedule 01.03.2014