Логическая проверка и проверка типов в python против numpy
Я столкнулся с неожиданными результатами в питоне if
статья сегодня:
import numpy
if numpy.allclose(6.0, 6.1, rtol=0, atol=0.5):
print 'close enough' # works as expected (prints message)
if numpy.allclose(6.0, 6.1, rtol=0, atol=0.5) is True:
print 'close enough' # does NOT work as expected (prints nothing)
После некоторого осмотра (т. Е. Этого вопроса и, в частности, этого ответа) я понимаю причину: type
вернулся numpy.allclose()
является numpy.bool_
а не старый bool
и, видимо, если foo = numpy.bool_(1)
, затем if foo
будет оценивать True
в то время как if foo is True
будет оценивать False
, Похоже, это работа is
оператор.
Мои вопросы: почему numpy имеет свой собственный логический тип, и что является наилучшей практикой в свете этой ситуации? Я могу сойти с рук в письменной форме if foo:
чтобы получить ожидаемое поведение в примере выше, но мне нравится более строгий if foo is True:
потому что это исключает такие вещи, как 2
а также [2]
от возвращения True
и иногда желательна явная проверка типа.
2 ответа
почему NumPy имеет свой логический тип
Пространство и скорость. Numpy хранит вещи в компактных массивах; если он может вписать логическое значение в один байт, он попытается. Вы не можете легко сделать это с объектами Python, так как вам нужно хранить ссылки, что значительно замедляет вычисления.
Я могу сойти с рук написав if foo: чтобы получить ожидаемое поведение в приведенном выше примере, но мне нравится более строгий, если foo равен True: потому что он исключает такие вещи, как 2 и [2], из возврата True, а иногда явная проверка типа желательно.
Ну, не делай этого.
Вы делаете что-то, что считается анти-паттерном. Цитата PEP 8:
Не сравнивайте логические значения с True или False, используя ==.
Yes: if greeting:
No: if greeting == True:
Worse: if greeting is True:
Тот факт, что NumPy не был разработан для облегчения вашего непитонического кода, не является ошибкой NUMPY. На самом деле, это прекрасный пример того, почему ваша личная идиома является анти-паттерном.
Как говорит PEP 8, используя is True
еще хуже чем == True
, Зачем? Потому что вы проверяете идентичность объекта: результат не только должен быть правдивым в логическом контексте (который обычно является всем, что вам нужно), и равен логическому True
значение, оно должно быть на самом деле постоянным True
, Трудно представить себе ситуацию, в которой это то, что вы хотите.
И вы специально не хотите это здесь:
>>> np.True_ == True
True
>>> np.True_ is True
False
Итак, все, что вы делаете, - это явно делаете свой код несовместимым с numpy и различными другими библиотеками расширений C (предположительно, библиотека с чистым Python может возвращать пользовательское значение, равное True
, но я не знаю ни одного, кто делает это).
В вашем конкретном случае нет причин исключать 2
а также [2]
, Если вы читаете документы для numpy.allclose
явно не собирается их возвращать. Но рассмотрим некоторые другие функции, например, многие из стандартных библиотек, которые просто говорят, что они оценивают как true или false. Это означает, что им явно разрешено возвращать один из своих правдивых аргументов, и часто это будет сделано. Почему вы хотите считать это ложным?
Наконец, почему numpy или любая другая библиотека расширений C определяют такие типы, совместимые с bool, но не bool?
В общем, это потому, что они обертывают C int, C++ bool или какой-то другой такой тип. В случае numpy, это оборачивает значение, которое может быть сохранено в типе слова с самым быстрым машинным словом или в одном байте (возможно, даже в одном бите в некоторых случаях) в зависимости от производительности, и вашему коду не нужно заботиться о том, какие, потому что все представления выглядят одинаково, включая правдивость и равенство True
постоянная.