Это поведение выглядело немного странно. Вот почему это происходит (и посмотрите, что является ошибкой, а что нет).
Во-первых, summation
- это просто синтактический c сахар для создание Sum
и запуск .doit()
. Sum
'doit
использует среди остальных eval_sum
, который извлекает предельные границы, когда предельная переменная не является свободной переменной функции, и простая проверка показывает, что действительно это должно быть здесь! (и, как вы показали, это не так):
>>> i in my_sum.free_symbols
False
, поэтому я немного покопался в модуле summation
.
Теперь, Sum
имеет родителя с именем AddWithLimits
. В своем создателе класса он использует функцию _common_new
, которая отменяет функцию, которую он получает .
Это превращает Sum(Sum(x[i], (i, 1, n)), (i, 1, n))
в Sum(x[i], (i, 1, n), (i, 1, n))
(задолго до вызова doit
), поэтому внутренняя функция - x[i]
, а не объект Sum
, который вы определили в my_sum
(который не ' t всплывает с первого взгляда), , поэтому предельная переменная фактически является свободной переменной функции .
Я пытался вручную отменить денестирование , комментируя три строки под комментарием # denest any nested calls
, и действительно, я получил
n*Sum(x[i], (i, 1, n))
Конечно, простое изменение, которое, вероятно, повредило бы другие части кода, поскольку деенестирование предполагается во многих других ExprWithLimits
функции. Является ли это предполагаемым поведением, можно утверждать в пользу , но если вы считаете, что его следует охватить, его, вероятно, следует явно указать внутри eval_sum
как особый случай.
Тем не менее, я ожидаю, что суммирование с другой переменной будет обычно упрощено, как
summation(x[i], (i, 1, n), (j, 1, n))
, что не так. Я подозреваю, что это больше предполагаемого поведения (что вызвано тем, что первая итерация по eval_sum
возвращает None
, поэтому пропускает расширение символа j
).