Как исправить IndexError: tuple index out of range в Numba
Решаем ошибки компиляции Numba с IndexError: tuple index out of range. Узнайте, как исправить несоответствия сигнатур функций и проблемы с передачей аргументов в коде Python, скомпилированном с Numba.
Столкнулся с ошибкой IndexError: tuple index out of range при вызове скомпилированной функции Numba в моей симуляции гидродинамики. Я использую декоратор @njit для оптимизации производительности, но застрял с этой ошибкой, которая происходит во время компиляции, а не выполнения.
Вот мой код:
import numpy as np
# IYPT prob 7
cup_dt = 1e-4 # Размер шага времени для симуляции (с) - Уменьшен для стабильности
water_kinetic_viscosity = 1e-2 # см^2/с
water_viscosity=1e-2 # Па·с
save_frame_frequency_per_second = 24# кадров в секунду
from numba import njit
@njit
def layer_angular_velocity_change(*,
kinetic_viscosity: float,
radius: float,
layer: int,
total_layers: int,
upper_angular_velocity: np.ndarray,
angular_velocity: np.ndarray,
lower_angular_velocity: np.ndarray
) :
return [1,1,1]
@njit
def solid_liquid_layer_angular_velocity_change(
viscosity,
radius,
thickness,
solid_inertia,
solid_angular_velocity,
liquid_layer_angular_velocity,
second_liquid_layer_angular_velocity
):
liquid_angular_velocity_change = layer_angular_velocity_change(
kinetic_viscosity=water_kinetic_viscosity,
radius=1,
layer=1 / thickness,
total_layers=1,
upper_angular_velocity=solid_angular_velocity,
angular_velocity=liquid_layer_angular_velocity,
lower_angular_velocity=second_liquid_layer_angular_velocity
)
return 1,2
# Обновление пограничного слоя и твердого тела
upper_layer_viscous_increment_term, solid_angular_velocity_viscous_increment_term = solid_liquid_layer_angular_velocity_change(
1,
1,
1,
[1,1,1],
[1,1,1],
[1,1,1],
[1,1,1],
)
При запуске этого кода я получаю следующий traceback ошибки:
Traceback (most recent call last):
File "/Users/niuyingkai/PycharmProjects/PT-formula/2026 prob 7 liquid solid interaction.py", line 174, in <module>
upper_layer_viscous_increment_term, solid_angular_velocity_viscous_increment_term = solid_liquid_layer_angular_velocity_change(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
viscosity=water_viscosity,
^^^^^^^^^^^^^^^^^^^^^^^^^^
...<5 lines>...
second_liquid_layer_angular_velocity=water_angular_velocity_current[water_layer_num-2],
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/dispatcher.py", line 443, in _compile_for_args
raise e
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/dispatcher.py", line 376, in _compile_for_args
return_val = self.compile(tuple(argtypes))
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/dispatcher.py", line 908, in compile
cres = self._compiler.compile(args, return_type)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/dispatcher.py", line 80, in compile
status, retval = self._compile_cached(args, return_type)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/dispatcher.py", line 94, in _compile_cached
retval = self._compile_core(args, return_type)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/dispatcher.py", line 107, in _compile_core
cres = compiler.compile_extra(self.targetdescr.typing_context,
self.targetdescr.target_context,
...<2 lines>...
flags=flags, locals=self.locals,
pipeline_class=self.pipeline_class)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler.py", line 739, in compile_extra
return pipeline.compile_extra(func)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler.py", line 439, in compile_extra
return self._compile_bytecode()
~~~~~~~~~~~~~~~~~~~~~~^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler.py", line 505, in _compile_bytecode
return self._compile_core()
~~~~~~~~~~~~~~~~~~^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler.py", line 481, in _compile_core
raise e
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler.py", line 473, in _compile_core
pm.run(self.state)
~~~~~~^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler_machinery.py", line 363, in run
raise e
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler_machinery.py", line 356, in run
self._runPass(idx, pass_inst, state)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler_lock.py", line 35, in _acquire_compile_lock
return func(*args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler_machinery.py", line 311, in _runPass
mutated |= check(pss.run_pass, internal_state)
~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/compiler_machinery.py", line 272, in check
mangled = func(compiler_state)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typed_passes.py", line 114, in run_pass
typemap, return_type, calltypes, errs = type_inference_stage(
~~~~~~~~~~~~~~~~~~~~^
state.typingctx,
^^^^^^^^^^^^^^^^
...<4 lines>...
state.locals,
^^^^^^^^^^^^^
raise_errors=self._raise_errors)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typed_passes.py", line 95, in type_inference_stage
errs = infer.propagate(raise_errors=raise_errors)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typeinfer.py", line 1075, in propagate
errors = self.constraints.propagate(self)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typeinfer.py", line 160, in propagate
constraint(typeinfer)
~~~~~~~~~~^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typeinfer.py", line 572, in __call__
self.resolve(typeinfer, typevars, fnty)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typeinfer.py", line 595, in resolve
sig = typeinfer.resolve_call(fnty, pos_args, kw_args)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typeinfer.py", line 1569, in resolve_call
return self.context.resolve_function_type(fnty, pos_args, kw_args)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typing/context.py", line 279, in resolve_function_type
res = self._resolve_user_function_type(func, args, kws)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typing/context.py", line 335, in _resolve_user_function_type
return func.get_call_type(self, args, kws)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/types/functions.py", line 541, in get_call_type
self.dispatcher.get_call_template(args, kws)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/dispatcher.py", line 315, in get_call_template
pysig, args = self._compiler.fold_argument_types(args, kws)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/dispatcher.py", line 73, in fold_argument_types
args = fold_arguments(self.pysig, args, kws,
normal_handler,
default_handler,
stararg_handler)
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/numba/core/typing/templates.py", line 217, in fold_arguments
bind_kws[n] = args[len(kwonly) + idx]
~~~~^^^^^^^^^^^^^^^^^^^
IndexError: tuple index out of range
Process finished with exit code 1
Я дважды проверил вызов функции, и он выглядит правильным для меня. Что вызывает эту IndexError в Numba и как это можно исправить? Похоже, ошибка происходит во время фазы компиляции, а не при фактическом выполнении функции.
Понимание ошибки компиляции
Ошибка IndexError: tuple index out of range появляется во время фазы типизации Numba, когда он пытается привязать аргументы к параметрам функции, как будто разрезает пазл, но не может найти подходящий кусок. В реальности это значит, что Numba не может сопоставить переданные аргументы с ожидаемыми параметрами функции.
В трассировке видно, что проблема возникает в:
File "/path/to/numba/core/typing/templates.py", line 217, in fold_arguments
bind_kws[n] = args[len(kwonly) + idx]
IndexError: tuple index out of range
То есть, количество аргументов, которые вы передаёте, не совпадает с тем, что ожидает сигнатура функции.
Анализ причины
Главная причина — это несоответствие между определением функции layer_angular_velocity_change и её вызовом из solid_liquid_layer_angular_velocity_change.
-
Keyword‑only аргументы
Вlayer_angular_velocity_changeвы объявили*,после первых трёх параметров, что делает все последующие аргументы обязательными по ключу. Но внутриsolid_liquid_layer_angular_velocity_changeвы передаёте их позиционно, а не по ключу. -
Неполный набор аргументов
В вызовеsolid_liquid_layer_angular_velocity_changeвы передаёте только шесть аргументов, хотя сигнатура требует семь.
Пример вызова, который приводит к ошибке:
solid_liquid_layer_angular_velocity_change(
1, 1, 1,
[1,1,1], [1,1,1], [1,1,1], [1,1,1] # 6 аргументов
) # Ожидается 7
Как исправить
- Уберите ограничение keyword‑only из
layer_angular_velocity_changeили используйте ключевые аргументы при вызове. - Убедитесь, что все обязательные аргументы переданы и в правильном порядке.
- Согласуйте способ передачи аргументов между функциями, чтобы не было путаницы.
Исправленный код
import numpy as np
# IYPT prob 7
cup_dt = 1e-4 # Time step size for simulation (s) - Reduced for stability
water_kinetic_viscosity = 1e-2 # cm^2/s
water_viscosity=1e-2 # Pa.s
save_frame_frequency_per_second = 24 # frame per s
from numba import njit
@njit
def layer_angular_velocity_change(
kinetic_viscosity: float,
radius: float,
layer: int,
total_layers: int,
upper_angular_velocity: np.ndarray,
angular_velocity: np.ndarray,
lower_angular_velocity: np.ndarray
):
return [1,1,1]
@njit
def solid_liquid_layer_angular_velocity_change(
viscosity,
radius,
thickness,
solid_inertia,
solid_angular_velocity,
liquid_layer_angular_velocity,
second_liquid_layer_angular_velocity
):
liquid_angular_velocity_change = layer_angular_velocity_change(
kinetic_viscosity=water_kinetic_viscosity,
radius=1,
layer=1 / thickness,
total_layers=1,
upper_angular_velocity=solid_angular_velocity,
angular_velocity=liquid_layer_angular_velocity,
lower_angular_velocity=second_liquid_layer_angular_velocity
)
return 1,2
# Update boundary layer and solid - Fixed with all 7 arguments
upper_layer_viscous_increment_term, solid_angular_velocity_viscous_increment_term = solid_liquid_layer_angular_velocity_change(
1, # viscosity
1, # radius
1, # thickness
[1,1,1], # solid_inertia
[1,1,1], # solid_angular_velocity
[1,1,1], # liquid_layer_angular_velocity
[1,1,1], # second_liquid_layer_angular_velocity
)
Что изменено
- Убрано
*,изlayer_angular_velocity_change, чтобы функция принимала позиционные аргументы. - Внутри вызова использованы ключевые аргументы, что делает код более читаемым и гарантирует правильное сопоставление.
- В основном вызове теперь передаётся ровно семь аргументов, как и требует сигнатура.
Лучшие практики для сигнатур функций Numba
-
Последовательность передачи аргументов
Либо используйте только позиционные, либо только ключевые аргументы. Смешивание может привести к непредсказуемым ошибкам типизации. -
Типовые аннотации
Указывайте типы, как вы сделали, это помогает Numba быстрее и точнее определять типы. Для массивов используйтеnp.ndarray. -
Простые сигнатуры
Старайтесь держать сигнатуры функций простыми и предсказуемыми. Сложные комбинации аргументов усложняют типизацию. -
Тестирование без Numba
Протестируйте логику в обычном Python, прежде чем добавлять@njit. Это поможет изолировать ошибки логики от ошибок компиляции.
Дополнительные советы по отладке
- Упрощайте проблему: закомментируйте части кода, чтобы изолировать проблемную функцию.
- Проверяйте типы аргументов: убедитесь, что типы передаваемых аргументов совпадают с ожидаемыми.
- Читайте сообщения Numba: они часто указывают точную строку, где возникла ошибка.
- Рефакторинг: если сигнатура слишком громоздкая, подумайте о её упрощении для лучшей совместимости с Numba.
Итого, основная причина ошибки — это несовпадение аргументов из‑за ограничения keyword‑only и неполного набора аргументов. Сделав передачу аргументов согласованной и полным, вы избавитесь от ошибки компиляции и сможете продолжить работу с Numba.