Правильный способ проверить 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

но два dtypes часто не являются:

>>> 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 и не castxx_) я получаю сообщение об ошибке:

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