Spec-Zone.ru › NumPy 2.0

Руководство по миграции на NumPy 2.0

Этот документ содержит набор инструкций по обновлению вашего кода для работы с NumPy 2.0. Он охватывает изменения в Python и C API NumPy.

Примечание

Обратите внимание, что NumPy 2.0 также нарушает двоичную совместимость — если вы распространяете двоичные файлы для пакета Python, зависящего от C API NumPy, ознакомьтесь со статьёй специфическими рекомендациями по NumPy 2.0.

Плагин Ruff

Многие изменения, описанные в заметках к релизу 2.0 и в этом руководстве по миграции, могут быть автоматически адаптированы в коде дочерних проектов с помощью специального правила Ruff, а именно правила NPY201.

Вы должны установить ruff>=0.4.8 и добавить правило NPY201 в ваш pyproject.toml:

[tool.ruff.lint]
select = ["NPY201"]

Вы также можете применить правило NumPy 2.0 непосредственно из командной строки:

$ ruff check path/to/code/ --select NPY201

Изменения в поощрении типов данных NumPy

NumPy 2.0 изменяет продвижение (результат сочетания несходных типов данных) в соответствии с NEP 50. Подробности об этом изменении вы найдете в NEP. Он включает таблицу примеров изменений и раздел обратной совместимости.

Наиболее существенное изменение обратной совместимости заключается в том, что точность скаляров теперь сохраняется последовательно. Вот два примера:

  • np.float32(3) + 3. теперь возвращает float32, в то время как раньше возвращал float64.
  • np.array([3], dtype=np.float32) + np.float64(3) теперь будет возвращать массив float64. (Более высокая точность скаляра не игнорируется.)

Для чисел с плавающей точкой это может привести к результатам с меньшей точностью при работе со скалярами. Для целых чисел возможны ошибки или переполнение.

Для решения этой проблемы вы можете явно выполнить приведение типа. Очень часто хорошим решением также является обеспечение работы с Python-скалярами с помощью int(), float(), или numpy_scalar.item().

Чтобы отследить изменения, вы можете включить выброс предупреждений об изменениях поведения (используйте warnings.simplefilter для повышения до уровня ошибки для трассировки стека):

np._set_promotion_state("weak_and_warn")

что полезно во время тестирования. К сожалению, выполнение этого может привести к обозначению многих изменений, которые на практике не имеют значения.

Значение по умолчанию для целых чисел в Windows

Целое число по умолчанию, используемое NumPy, теперь равно 64-битному на всех 64-битных системах (и 32-битному на 32-битных системах). По историческим причинам, связанным с Python 2, ранее оно было эквивалентно типу C long. Теперь значение по умолчанию эквивалентно np.intp.

В большинстве случаев конечные пользователи не должны ощущать влияния этого изменения. Некоторые операции будут использовать больше памяти, но некоторые операции могут фактически стать быстрее. Если у вас возникнут проблемы из-за вызова библиотеки, написанной на языке скомпилированном на низком уровне, это может помочь явно приведение к типу long, например, с помощью: arr = arr.astype("long", copy=False).

Библиотекам, взаимодействующим с скомпилированным кодом, написанным на C, Cython или подобном языке, может потребоваться обновление для адаптации входных данных пользователя, если они используют тип long или эквивалентный тип со стороны C. В этом случае вы можете использовать intp и привести данные пользователя к типу или поддержать оба типа long и intp (для лучшей поддержки NumPy 1.x также). При создании нового массива целых чисел в C или Cython новая макрокоманда NPY_DEFAULT_INT будет оцениваться либо как NPY_LONG, либо как NPY_INTP, в зависимости от версии NumPy.

Обратите внимание, что API NumPy для генерации случайных чисел не затрагивается этим изменением.

Изменения в C-API

Некоторые определения были удалены или заменены из-за устаревания или невозможности поддержки. Некоторые новые определения API будут оцениваться по-разному во время выполнения между NumPy 2.0 и NumPy 1.x. Некоторые из них определены в numpy/_core/include/numpy/npy_2_compat.h (например, NPY_DEFAULT_INT) и могут быть полностью или частично переданы для того, чтобы определения были доступны при компиляции с NumPy 1.x.

При необходимости PyArray_RUNTIME_VERSION >= NPY_2_0_API_VERSION можно использовать для явного реализации различного поведения в NumPy 1.x и 2.0. (Заголовочный файл compat определяет его так, чтобы он был совместим с таким использованием.)

Пожалуйста, сообщите нам, если вам потребуются дополнительные решения.

Структура PyArray_Descr изменена

Одно из самых значительных изменений в C-API заключается в том, что структура PyArray_Descr теперь более непрозрачна, что позволяет добавить дополнительные флаги и иметь размер элементов, не ограниченный размером int, а также позволяет улучшить структурированные типы данных в будущем, не накладывая дополнительные ограничения на новые типы данных с их полями.

Код, использующий только номер типа и другие исходные поля, не затрагивается. Большинство кода, скорее всего, будет в основном обращаться к полю ->elsize, когда сам тип данных/описатель присоединён к массиву (например, arr->descr->elsize) это лучше заменить на PyArray_ITEMSIZE(arr).

В тех случаях, когда это невозможно, требуются новые функции доступа:

  • PyDataType_ELSIZE и PyDataType_SET_ELSIZE (обратите внимание, что результат теперь npy_intp, а не int).
  • PyDataType_ALIGNMENT
  • PyDataType_FIELDS, PyDataType_NAMES, PyDataType_SUBARRAY
  • PyDataType_C_METADATA

Код Cython должен использовать Cython 3, в этом случае изменение будет прозрачным. (Доступ к структуре доступен для elsize и выравнивания при компиляции только для NumPy 2.)

Для компиляции как с 1.x, так и с 2.x, если вы используете эти новые функции доступа, к сожалению, необходимо либо определить их локально с помощью макроса, например:

#if NPY_ABI_VERSION < 0x02000000
  #define PyDataType_ELSIZE(descr) ((descr)->elsize)
#endif

или добавить npy2_compat.h в свой код и явно включить его при компиляции с NumPy 1.x (так как они являются новыми API). Включение файла не повлияет на NumPy 2.

Пожалуйста, не стесняйтесь открывать вопрос в системе отслеживания задач NumPy, если вам требуется помощь или предоставленных функций недостаточно.

Пользовательские типы данных: Теперь существующие пользовательские типы данных должны использовать PyArray_DescrProto для определения типа данных и немного изменить код. См. примечание в PyArray_RegisterDataType.

Функциональность перемещена в заголовочные файлы, требующие import_array()

Если вы ранее включали только ndarraytypes.h, вы можете обнаружить, что некоторые функции больше недоступны и требуют включения ndarrayobject.h или аналогичных. Это включение также необходимо при передаче npy_2_compat.h в ваш собственный набор кода для поддержки использования новых определений при компиляции с NumPy 1.x.

Функции, которые ранее не требовали включения:

  • Функции для доступа к флагам типа данных: PyDataType_FLAGCHK, PyDataType_REFCHK, и связанные NPY_BEGIN_THREADS_DESCR.
  • PyArray_GETITEM и PyArray_SETITEM.

Предупреждение

Важно использовать механизм import_array() для обеспечения доступа ко всему API NumPy при использовании заголовочного файла npy_2_compat.h. В большинстве случаев ваш модуль расширения, вероятно, уже вызывает его. Однако, если нет, мы добавили PyArray_ImportNumPyAPI() как предпочтительный способ обеспечения импорта API NumPy. Эта функция легкая при многократном вызове, поэтому вы можете вставить её везде, где это необходимо (если вы хотите избежать её настройки при импорте модуля).

Увеличено максимальное количество измерений

Максимальное количество измерений (и аргументов) увеличено до 64. Это затрагивает макросы NPY_MAXDIMS и NPY_MAXARGS. Возможно, стоит пересмотреть их использование, и мы в целом рекомендуем не использовать эти макросы (особенно NPY_MAXARGS), чтобы в будущих версиях NumPy можно было снять это ограничение на количество измерений.

NPY_MAXDIMS также использовалось для обозначения axis=None в C-API, включая PyArray_AxisConverter. Последнее вернёт -2147483648 в качестве оси (наименьшее целое значение). Другие функции могут возвращать ошибку AxisError: axis 64 is out of bounds for array of dimension, в этом случае необходимо передать NPY_RAVEL_AXIS, а не NPY_MAXDIMS. NPY_RAVEL_AXIS определён в заголовочном файле npy_2_compat.h и зависит от времени выполнения (сопоставление с 32 на NumPy 1.x и -2147483648 на NumPy 2.x).

Комплексные типы - Изменения базового типа

Базовые C-типы для всех комплексных типов были изменены для использования собственных C99-типов. Хотя структура памяти этих типов остаётся идентичной типам, используемым в NumPy 1.x, API немного отличается, так как прямой доступ к полям (например, c.real или c.imag) больше недоступен.

Рекомендуется использовать функции npy_creal и npy_cimag (и соответствующие варианты для float и long double), чтобы извлечь действительную или мнимую часть комплексного числа, так как они будут работать как с NumPy 1.x, так и с NumPy 2.x. Были добавлены новые функции npy_csetreal и npy_csetimag, а также макросы совместимости NPY_CSETREAL и NPY_CSETIMAG (и соответствующие варианты для float и long double), для установки действительной или мнимой части.

Базовый тип остаётся структурой в C++ (всё вышеперечисленное остаётся справедливым).

Это имеет последствия для Cython. Рекомендуется всегда использовать собственные типы cfloat_t, cdouble_t, clongdouble_t вместо типов NumPy npy_cfloat, и т. д., если только вы не должны взаимодействовать с C-кодом, написанным с использованием типов NumPy. Вы всё ещё можете писать код Cython, используя атрибуты c.real и c.imag (используя собственные типы), но вы больше не можете использовать операторы на месте c.imag += 1 в режиме c++ Cython.

Изменения в именованных пространствах

В NumPy 2.0 некоторые функции, модули и константы были перемещены или удалены, чтобы сделать пространство имен NumPy более удобным для пользователя, удалив ненужную или устаревшую функциональность и прояснив, какие части NumPy считаются частными. См. таблицы ниже для руководства по миграции. Для большинства изменений это означает замену на обратно совместимую альтернативу.

Обратитесь к NEP 52 для получения более подробной информации.

Основное пространство имен

Около 100 членов основного np пространства имен были помечены как устаревшие, удалены или перемещены в новое место. Это было сделано для уменьшения беспорядка и установления только одного способа доступа к заданному атрибуту. В таблице ниже показаны удаленные члены:

Удаленный член

Рекомендации по миграции

add_docstring

Он по-прежнему доступен как np.lib.add_docstring.

add_newdoc

Он по-прежнему доступен как np.lib.add_newdoc.

add_newdoc_ufunc

Это внутренняя функция, и у нее нет замены.

alltrue

Используйте all вместо этого.

asfarray

Используйте np.asarray с типом данных float вместо этого.

byte_bounds

Теперь он доступен в np.lib.array_utils.byte_bounds

cast

Используйте np.asarray(arr, dtype=dtype) вместо этого.

cfloat

Используйте np.complex128 вместо этого.

clongfloat

Используйте np.clongdouble вместо этого.

compat

Замены нет, так как Python 2 больше не поддерживается.

complex_

Используйте np.complex128 вместо этого.

cumproduct

Используйте np.cumprod вместо этого.

DataSource

Он по-прежнему доступен как np.lib.npyio.DataSource.

deprecate

Вызовите DeprecationWarning с warnings.warn напрямую или используйте typing.deprecated.

deprecate_with_doc

Вызовите DeprecationWarning с warnings.warn напрямую или используйте typing.deprecated.

disp

Используйте свою собственную функцию вывода.

fastCopyAndTranspose

Используйте arr.T.copy() вместо этого.

find_common_type

Используйте numpy.promote_types или numpy.result_type вместо этого. Для достижения семантики для аргумента scalar_types, используйте numpy.result_type и передайте значения Python 0, 0.0, или 0j.

get_array_wrap

float_

Используйте np.float64 вместо этого.

geterrobj

Используйте менеджер контекста np.errstate вместо этого.

Inf

Используйте np.inf вместо этого.

Infinity

Используйте np.inf вместо этого.

infty

Используйте np.inf вместо этого.

issctype

Используйте issubclass(rep, np.generic) вместо этого.

issubclass_

Используйте встроенную функцию issubclass вместо этого.

issubsctype

Используйте np.issubdtype вместо этого.

mat

Используйте np.asmatrix вместо этого.

maximum_sctype

Используйте конкретный тип данных вместо этого. Вам следует избегать использования каких-либо неявных механизмов и явно выбрать наибольший тип данных определенного вида в коде.

NaN

Используйте np.nan вместо этого.

nbytes

Используйте np.dtype(<dtype>).itemsize вместо этого.

NINF

Используйте -np.inf вместо этого.

NZERO

Используйте -0.0 вместо этого.

longcomplex

Используйте np.clongdouble вместо этого.

longfloat

Используйте np.longdouble вместо этого.

lookfor

Используйте прямую поиск в документации NumPy.

obj2sctype

Используйте np.dtype(obj).type вместо этого.

PINF

Используйте np.inf вместо этого.

product

Используйте np.prod вместо этого.

PZERO

Используйте 0.0 вместо этого.

recfromcsv

Используйте np.genfromtxt с разделителем запятой вместо этого.

recfromtxt

Используйте np.genfromtxt вместо этого.

round_

Используйте np.round вместо этого.

safe_eval

Используйте ast.literal_eval вместо этого.

sctype2char

Используйте np.dtype(obj).char вместо этого.

sctypes

Доступ к типам данных напрямую вместо этого.

seterrobj

Используйте менеджер контекста np.errstate вместо этого.

set_numeric_ops

В общем случае используйте PyUFunc_ReplaceLoopBySignature. Для подклассов ndarray определите метод __array_ufunc__ и переопределите соответствующий ufunc.

set_string_function

Используйте np.set_printoptions вместо этого с форматером для пользовательского вывода объектов NumPy.

singlecomplex

Используйте np.complex64 вместо этого.

string_

Используйте np.bytes_ вместо этого.

sometrue

Используйте any вместо этого.

source

Используйте inspect.getsource вместо этого.

tracemalloc_domain

Он теперь доступен из np.lib.

unicode_

Используйте np.str_ вместо этого.

who

Используйте обозреватель переменных IDE или locals() вместо этого.

Если в таблице нет элемента, который вы использовали, но который был удален в 2.0, это означает, что это был частный член. Вы должны либо использовать существующий API, либо, если это невозможно, обратиться к нам с запросом о восстановлении удаленного элемента.

В следующей таблице представлены устаревшие члены, которые будут удалены в релизе после 2.0:

Устаревший член

Рекомендации по миграции

in1d

Используйте np.isin вместо этого.

row_stack

Используйте np.vstack вместо этого (row_stack был псевдонимом для vstack).

trapz

Используйте np.trapezoid или функцию scipy.integrate вместо этого.

Наконец, набор внутренних перечислений был удален. Поскольку они не использовались в библиотеках нижнего уровня, мы не предоставляем информации о том, как их заменить:

[FLOATING_POINT_SUPPORT, FPE_DIVIDEBYZERO, FPE_INVALID, FPE_OVERFLOW, FPE_UNDERFLOW, UFUNC_BUFSIZE_DEFAULT, UFUNC_PYVALS_NAME, CLIP, WRAP, RAISE, BUFSIZE, ALLOW_THREADS, MAXDIMS, MAY_SHARE_EXACT, MAY_SHARE_BOUNDS]

Пространство имен numpy.lib

Большинство функций, доступных в np.lib, также присутствуют в основном пространстве имен, которое является их основным местоположением. Чтобы однозначно указать, как получить доступ к каждой публичной функции, np.lib теперь пуст и содержит только несколько специализированных подмодулей, классов и функций:

  • array_utils, format, introspect, mixins, npyio и stride_tricks подмодули,
  • Arrayterator и NumpyVersion классы,
  • add_docstring и add_newdoc функции,
  • tracemalloc_domain константа.

Если при обращении к атрибуту из np.lib вы получаете AttributeError, попробуйте получить к нему доступ из основного пространства имен np вместо этого. Если элемент также отсутствует в основном пространстве имен, значит, вы используете частный член. Вы должны либо использовать существующий API, либо, если это невозможно, обратиться к нам с запросом о восстановлении удаленного элемента.

Пространство имен numpy.core

Пространство имен np.core теперь официально является закрытым и было переименовано в np._core. Пользователь никогда не должен извлекать члены из _core напрямую — вместо этого основное пространство имен должно использоваться для доступа к нужному атрибуту. Структура модуля _core может измениться в будущем без предварительного уведомления, в отличие от общедоступных модулей, которые придерживаются политики отмены устаревания.

Если элемент также отсутствует в основном пространстве имен, то вы должны либо использовать существующий API, либо, в случае невозможности, обратиться к нам с запросом о восстановлении удаленного элемента.

Методы ndarray и скаляров

Были удалены несколько методов из np.ndarray и np.generic классов скаляров. В таблице ниже приведены замены для удаленных членов:

Устаревший член

Рекомендации по миграции

newbyteorder

Используйте arr.view(arr.dtype.newbyteorder(order)) вместо этого.

ptp

Используйте np.ptp(arr, ...) вместо этого.

setitem

Используйте arr[index] = value вместо этого.

Пространство имён numpy.strings

Было создано новое numpy.strings пространство имён, где большинство строковых операций реализованы как ufunc. Старое пространство имён numpy.char всё ещё доступно и, где это возможно, использует новые ufunc для повышения производительности. Рекомендуется использовать функции strings в дальнейшем. Пространство имён char может быть устаревшим в будущем.

Другие изменения

Примечание о файлах pickle

NumPy 2.0 разработан для загрузки файлов pickle, созданных с помощью NumPy 1.26, и наоборот. Для версий 1.25 и более ранних загрузка файла pickle NumPy 2.0 вызовет исключение.

Адаптация к изменениям в ключевом слове copy

Изменения в поведении ключевого слова copy в asarray, array и ndarray.__array__ могут потребовать этих изменений:

  • Код, использующий np.array(..., copy=False), в большинстве случаев может быть изменён на np.asarray(...). Старый код, как правило, использовал np.array таким образом, поскольку это имело меньшую нагрузку, чем по умолчанию np.asarray поведение copy-if-needed. Это больше неверно, и np.asarray является предпочтительной функцией.
  • Для кода, которому явно нужно передать None/False, означающее «копировать при необходимости» способом, совместимым с NumPy 1.x и 2.x, см. scipy#20172 для примера.
  • Для любого метода __array__ на объекте, не являющемся массивом NumPy, ключевые слова dtype=None и copy=None должны быть добавлены в сигнатуру — это будет работать и со старыми версиями NumPy (хотя старые версии NumPy никогда не передадут ключевое слово copy). Если ключевые слова добавлены в сигнатуру __array__, то для:

    • copy=True и любого значения dtype всегда возвращается новая копия,
    • copy=None создаётся копия при необходимости (например, dtype),
    • copy=False копия никогда не должна создаваться. Если копия необходима для возвращения массива numpy или удовлетворения dtype, то должно быть выброшено исключение (ValueError).

Написание кода, зависящего от версии numpy

Редко требуется писать код, который явно разветвляется на основе версии numpy — в большинстве случаев код можно переписать так, чтобы он был совместим с 1.x и 2.0 одновременно. Однако, если это необходимо, вот предлагаемый шаблон кода, использующий numpy.lib.NumpyVersion:

# example with AxisError, which is no longer available in
# the main namespace in 2.0, and not available in the
# `exceptions` namespace in <1.25.0 (example uses <2.0.0b1
# for illustrative purposes):
if np.lib.NumpyVersion(np.__version__) >= '2.0.0b1':
    from numpy.exceptions import AxisError
else:
    from numpy import AxisError

Этот шаблон будет работать корректно, включая кандидаты на выпуск NumPy, что важно во время периода выпуска 2.0.0.

© 2005–2024 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/2.0/numpy_2_0_migration_guide.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API