Руководство по переходу на 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 для подробностей об этом изменении. Он включает таблицу примеров изменений и раздел обратной совместимости.

Это задокументированное поведение, но ранее результат мог быть любым из среза, None или списка.

  • 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. (Заголовок совместимости определяет его способом, совместимым с таким использованием.)

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

The PyArray_Descr структура была изменена#

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

Код, который использует только номер типа и другие начальные поля, не затрагивается. Большая часть кода, надеюсь, будет в основном обращаться к ->elsize поле, когда сам dtype/дескриптор прикреплен к массиву (например, 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.

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

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

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

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

Функциональность, которая ранее не требовала импорта, включает:

  • Функции для доступа к флагам dtype: 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. Рекомендуется всегда использовать нативные typedefs cfloat_t, cdouble_t, clongdouble_t вместо типов NumPy npy_cfloat, и т.д., если только вам не нужно взаимодействовать с кодом на C, написанным с использованием типов NumPy. Вы всё ещё можете писать код на Cython, используя c.real и c.imag атрибуты (с использованием нативных typedef), но вы больше не можете использовать операторы на месте c.imag += 1 в режиме c++ Cython.

Поскольку NumPy 2 теперь включает complex.h код, использующий переменную с именем I может появиться ошибка, например

использовать имя I требует #undef I сейчас.

Примечание

NumPy 2.0.1 кратко включал #undef I для помощи пользователям, которые еще не включают complex.h.

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

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

Пожалуйста, обратитесь к NEP 52 — Очистка Python API для NumPy 2.0 для получения дополнительной информации.

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

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

удалённый член

руководство по миграции

add_docstring

Он всё ещё доступен как np.lib.add_docstring.

add_newdoc

Он всё ещё доступен как np.lib.add_newdoc.

add_newdoc_ufunc

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

alltrue

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

asfarray

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

byte_bounds

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

преобразовать

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

cfloat

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

charrarray

Он всё ещё доступен как np.char.chararray.

clongfloat

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

compare_chararrays

Он всё ещё доступен как np.char.compare_chararrays.

compat

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

complex_

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

кумулятивное произведение

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

DataSource

Он всё ещё доступен как np.lib.npyio.DataSource.

устаревает

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

deprecate_with_doc

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

disp

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

fastCopyAndTranspose

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

найти_общий_тип

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

format_parser

Он всё ещё доступен как np.rec.format_parser.

get_array_wrap

float_

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

geterrobj

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

Inf

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

Бесконечность

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

бесконечность

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

issctype

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

issubclass_

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

issubsctype

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

mat

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

maximum_sctype

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

NaN

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

nbytes

Используйте np.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

Обращайтесь к dtypes явно.

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

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

источник

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

tracemalloc_domain

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

unicode_

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

кто

Используйте обозреватель переменных 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, scimath и stride_tricks подмодули,

  • Arrayterator и NumpyVersion классы,

  • add_docstring и add_newdoc функции,

  • tracemalloc_domain random.chisquare() (в модуле numpy)

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

пространство имён numpy.core#

The 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 пространство имён всё ещё доступно и, где возможно, использует новые ufuncs для большей производительности. Мы рекомендуем использовать strings функции в будущем. The char пространство имён может быть устаревшим в будущем.

Прочие изменения#

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

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

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

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

  • Использование кода np.array(..., copy=False) в большинстве случаев может быть заменена на np.asarray(...). Старый код обычно использовал np.array так, потому что это имело меньшие накладные расходы, чем по умолчанию np.asarray поведение копирования-при-необходимости. Это больше не верно, и np.asarray является предпочтительной функцией.

  • Для кода, которому явно нужно передавать None/False означает "копировать при необходимости" способом, совместимым с NumPy 1.x и 2.x, см. scipy#20172 для примера того, как это сделать.

  • Для любого __array__ метод на объекте, подобном массиву, но не NumPy, dtype=None и copy=None ключевые слова должны быть добавлены в сигнатуру — это будет работать и со старыми версиями NumPy (хотя старые версии numpy никогда не передадут copy ключевое слово). Если ключевые слова добавлены к __array__ сигнатура, затем для:

    • copy=True и любые dtype value всегда возвращает новую копию,

    • 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.