Руководство по миграции на 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 | Он по-прежнему доступен как |
add_newdoc | Он по-прежнему доступен как |
add_newdoc_ufunc | Это внутренняя функция, и у нее нет замены. |
alltrue | Используйте |
asfarray | Используйте |
byte_bounds | Теперь он доступен в |
cast | Используйте |
cfloat | Используйте |
clongfloat | Используйте |
compat | Замены нет, так как Python 2 больше не поддерживается. |
complex_ | Используйте |
cumproduct | Используйте |
DataSource | Он по-прежнему доступен как |
deprecate | Вызовите |
deprecate_with_doc | Вызовите |
disp | Используйте свою собственную функцию вывода. |
fastCopyAndTranspose | Используйте |
find_common_type | Используйте |
get_array_wrap | |
float_ | Используйте |
geterrobj | Используйте менеджер контекста np.errstate вместо этого. |
Inf | Используйте |
Infinity | Используйте |
infty | Используйте |
issctype | Используйте |
issubclass_ | Используйте встроенную функцию |
issubsctype | Используйте |
mat | Используйте |
maximum_sctype | Используйте конкретный тип данных вместо этого. Вам следует избегать использования каких-либо неявных механизмов и явно выбрать наибольший тип данных определенного вида в коде. |
NaN | Используйте |
nbytes | Используйте |
NINF | Используйте |
NZERO | Используйте |
longcomplex | Используйте |
longfloat | Используйте |
lookfor | Используйте прямую поиск в документации NumPy. |
obj2sctype | Используйте |
PINF | Используйте |
product | Используйте |
PZERO | Используйте |
recfromcsv | Используйте |
recfromtxt | Используйте |
round_ | Используйте |
safe_eval | Используйте |
sctype2char | Используйте |
sctypes | Доступ к типам данных напрямую вместо этого. |
seterrobj | Используйте менеджер контекста np.errstate вместо этого. |
set_numeric_ops | В общем случае используйте |
set_string_function | Используйте |
singlecomplex | Используйте |
string_ | Используйте |
sometrue | Используйте |
source | Используйте |
tracemalloc_domain | Он теперь доступен из |
unicode_ | Используйте |
who | Используйте обозреватель переменных IDE или |
Если в таблице нет элемента, который вы использовали, но который был удален в 2.0, это означает, что это был частный член. Вы должны либо использовать существующий API, либо, если это невозможно, обратиться к нам с запросом о восстановлении удаленного элемента.
В следующей таблице представлены устаревшие члены, которые будут удалены в релизе после 2.0:
Устаревший член | Рекомендации по миграции |
|---|---|
in1d | Используйте |
row_stack | Используйте |
trapz | Используйте |
Наконец, набор внутренних перечислений был удален. Поскольку они не использовались в библиотеках нижнего уровня, мы не предоставляем информации о том, как их заменить:
[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 | Используйте |
ptp | Используйте |
setitem | Используйте |
Пространство имён 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