Ответ 1
Параметр out
функции numpy - это массив, в котором записывается результат. Основным преимуществом использования out
является исключение выделения новой памяти там, где это необязательно.
Безопасно ли использовать запись функции в том же массиве, который передается как вход? Нет общего ответа, это зависит от того, что делает функция.
Два примера
Вот два примера ufunc-подобных функций:
In [1]: def plus_one(x, out=None):
...: if out is None:
...: out = np.zeros_like(x)
...:
...: for i in range(x.size):
...: out[i] = x[i] + 1
...: return out
...:
In [2]: x = np.arange(5)
In [3]: x
Out[3]: array([0, 1, 2, 3, 4])
In [4]: y = plus_one(x)
In [5]: y
Out[5]: array([1, 2, 3, 4, 5])
In [6]: z = plus_one(x, x)
In [7]: z
Out[7]: array([1, 2, 3, 4, 5])
Функция shift_one
:
In [11]: def shift_one(x, out=None):
...: if out is None:
...: out = np.zeros_like(x)
...:
...: n = x.size
...: for i in range(n):
...: out[(i+1) % n] = x[i]
...: return out
...:
In [12]: x = np.arange(5)
In [13]: x
Out[13]: array([0, 1, 2, 3, 4])
In [14]: y = shift_one(x)
In [15]: y
Out[15]: array([4, 0, 1, 2, 3])
In [16]: z = shift_one(x, x)
In [17]: z
Out[17]: array([0, 0, 0, 0, 0])
Для функции plus_one
нет проблемы: ожидаемый результат получается, когда параметры x и out являются одним и тем же массивом. Но функция shift_one
дает удивительный результат, когда параметры x и out являются одним и тем же массивом, потому что массив
Обсуждение
Для функции формы out[i] := some_operation(x[i])
, такой как plus_one
выше, но также функции floor, ceil, sin, cos, tan, log, conj и т.д., насколько я знаю, безопасно, чтобы записать результат на вход, используя параметр out.
Он также безопасен для функций, принимающих два входных параметра формы `` out [i]: = some_operation (x [i], y [i]), такие как функция numpy add, умножить, вычесть.
Для других функций это зависит от конкретного случая. Как показано ниже, матричное умножение небезопасно:
In [18]: a = np.arange(4).reshape((2,2))
In [19]: a
Out[19]:
array([[0, 1],
[2, 3]])
In [20]: b = (np.arange(4) % 2).reshape((2,2))
In [21]: b
Out[21]:
array([[0, 1],
[0, 1]], dtype=int32)
In [22]: c = np.dot(a, b)
In [23]: c
Out[23]:
array([[0, 1],
[0, 5]])
In [24]: d = np.dot(a, b, out=a)
In [25]: d
Out[25]:
array([[0, 1],
[0, 3]])
Последнее замечание:, если реализация многопоточная, результат небезопасной функции может даже быть недетерминированным, поскольку он зависит от порядка обработки элементов массива.