Правильный способ проверить numpy.dtype
Я смотрю на сторонний lib, который имеет следующее if
тест:
if isinstance(xx_, numpy.ndarray) and xx_.dtype is numpy.float64 and xx_.flags.contiguous:
xx_[:] = ctypes.cast(xx_.ctypes._as_parameter_,ctypes.POINTER(ctypes.c_double))
получается, что xx_.dtype is numpy.float64
всегда терпит неудачу:
>>> xx_ = numpy.zeros(8, dtype=numpy.float64)
>>> xx_.dtype is numpy.float64
False
каков правильный способ проверить, что dtype
массива numpy является float64
?
2 ответов
это ошибка в lib.
dtype
объекты может создаваться динамически. И NumPy делает это все время. Нет никакой гарантии, что они интернированы, поэтому построение dtype
то, что уже существует, даст вам то же самое.
на np.float64
на самом деле не dtype
; это... я не знаю, как называются эти типы, но типы, используемые для построения скалярных объектов из байтов массива, которые обычно находятся в the на dtype
, поэтому я назову это dtype.type
. (Обратите внимание, что np.float64
подклассы как числовые типы башни NumPy и числовые башни Python ABCs, в то время как np.dtype
конечно нет.)
обычно вы можете использовать их взаимозаменяемо; когда вы используете dtype.type
- или, если на то пошло, собственный числовой тип Python-где dtype
ожидалось, a dtype
строится на лету (что, опять же, не гарантируется интернированием), но, конечно, это не означает они идентичны:
>>> np.float64 == np.dtype(np.float64) == np.dtype('float64')
True
>>> np.float64 == np.dtype(np.float64).type
True
на dtype.type
обычно будет будьте идентичны, если вы используете встроенные типы:
>>> np.float64 is np.dtype(np.float64).type
True
но два dtype
s часто не являются:
>>> np.dtype(np.float64) is np.dtype('float64')
False
но опять же, ничего из этого не гарантируется. (Также обратите внимание, что np.float64
и float
используйте точно такое же хранилище, но отдельные типы. И конечно, вы также можете сделать dtype('f8')
, который гарантированно работает так же, как dtype(np.float64)
, но это не значит 'f8'
is
, или даже ==
, np.float64
.)
таким образом, возможно, что построение массива путем явной передачи np.float64
как его dtype
аргумент будет означать, что вы получите тот же экземпляр при проверке dtype.type
атрибут, но это не гарантируется. И если вы пройдете np.dtype('float64')
, или вы просите NumPy вывести его из данных, или вы передаете строку dtype для разбора, как 'f8'
, etc. еще менее вероятно совпадение. Что еще более важно, вы наверняка не получается np.float64
обратно как .
Итак, как это должно быть исправлено?
ну, документы определяют, что это значит для двух dtype
С равной, и это полезная вещь, и я думаю, что это, вероятно, полезная вещь, которую вы ищете здесь. Итак, просто замените is
С ==
:
if isinstance(xx_, numpy.ndarray) and xx_.dtype == numpy.float64 and xx_.flags.contiguous:
тем не менее, в какой-то степени я только предполагаю, что это то, что вы ищете. (Тот факт, что он проверяет смежный флаг, означает, что это вероятно, он пойдет прямо во внутреннее хранилище... но тогда почему он не проверяет порядок C против Fortran, или порядок байтов, или что-нибудь еще?)
попробуй:
x = np.zeros(8, dtype=np.float64)
print x.dtype is np.dtype(np.float64))
is
тесты для идентификации 2 объектов, имеют ли они то же самое id()
. Он используется, например, для проверки is None
, но может давать ошибки при тестировании целых чисел или строк. Но в этом случае есть еще одна проблема, x.dtype
и np.float64
не являются одним и тем же классом.
isinstance(x.dtype, np.dtype) # True
isinstance(np.float64, np.dtype) # False
x.dtype.__class__ # numpy.dtype
np.float64.__class__ # type
np.float64
на самом деле функция. np.float64()
производит 0.0
. x.dtype()
выдает ошибку. (поправка np.float64
- это класс.)
в моих интерактивных тестах:
x.dtype is np.dtype(np.float64)
возвращает True
. Но я не знаю, является ли это универсальным случаем или просто результатом какого-то локального кэширования. The dtype
в документации упоминается a :
dtype.num уникальный номер для каждого из 21 различных встроенных типов.
как dtypes дать 12
для этого num
.
x.dtype == np.float64
тесты True
.
также, используя type
работает:
x.dtype.type is np.float64 # True
когда я импортирую ctypes
и не cast
(С xx_
) я получаю сообщение об ошибке:
ValueError: установка элемента массива с последовательностью.
я не знаю достаточно о ctypes
чтобы понять, что он пытается сделать. Похоже, что он выполняет преобразование типа data
стрелка xx_
, xx_.ctypes._as_parameter_
такое же число как xx_.__array_interface__['data'][0]
.
на numpy
тестовый код я нахожу эти тесты dtype:
issubclass(arr.dtype.type, (nt.integer, nt.bool_)
assert_(dat.dtype.type is np.float64)
assert_equal(A.dtype.type, np.unicode_)
assert_equal(r['col1'].dtype.kind, 'i')
numpy
документация также говорит о
np.issubdtype(x.dtype, np.float64)
np.issubsctype(x, np.float64)
использования issubclass
.
дальнейшее отслеживание c
код говорит о том, что x.dtype == np.float64
оценивается как:
x.dtype.num == np.dtype(np.float64).num
то есть скалярный тип преобразуется в dtype
и .num
атрибуты по сравнению. Код в scalarapi.c
, descriptor.c
, multiarraymodule.c
of numpy / core / src / multiarray