Alteração da matriz NumPy em uma função [duplicar]

Sep 29 2020

O seguinte código

def change(in_array):

    in_array += 1             # line a

    in_array = in_array + 1   # line b


x = np.array([1, 2, 3])
change(x)
print(x)

impressões [2 3 4]. Por que isso acontece (por que as duas linhas aeb são diferentes)? Você poderia sugerir outras maneiras de modificar a matriz NumPy como é feito na linha a? Uma maneira seria in_array[:] = in_array + 1; os valores do passado na matriz sempre seriam alterados no caso de in_array[:] = ...?

Respostas

Arty Sep 28 2020 at 22:35

Vamos ver o próximo código:

Experimente online!

import numpy as np

def change(in_array, variant = 0):
    if variant == 0:
        in_array += 1             # line a
    elif variant == 1:
        in_array = in_array + 1   # line b
    elif variant == 2:
        in_array[:] = in_array + 1
    elif variant == 3:
        np.put(in_array, np.arange(in_array.size), in_array + 1)
    elif variant == 4:
        np.copyto(in_array, in_array + 1)
    elif variant == 5:
        np.place(in_array, np.ones_like(in_array), in_array + 1)
    else:
        assert False, variant
    print('after, inside', in_array)

orig = np.array([1, 2, 3])
for variant in [0, 1, 2, 3, 4, 5]:
    print('variant', variant)
    x = np.copy(orig)
    print('before', x)
    change(x, variant)
    print('after, outside', x, ('changed', 'not changed')[bool(np.all(x == orig))])

Ele produz:

variant 0
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
variant 1
before [1 2 3]
after, inside [2 3 4]
after, outside [1 2 3] not changed
variant 2
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
variant 3
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
variant 4
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed
variant 5
before [1 2 3]
after, inside [2 3 4]
after, outside [2 3 4] changed

Você pode ver que a variante 0 dá a resposta correta após a resposta interna e externa. Enquanto a variante 1 dá correto apenas no interior.

Isso ocorre porque a variante 0 modifica a matriz realmente fornecida que foi fornecida na função. Enquanto a variante 1 cria uma cópia modificada dentro da função que permanece apenas dentro da função, o argumento real passado não é modificado.

Portanto, a variante 0 modifica o argumento passado, enquanto a variante 1 modifica uma cópia do argumento passado.

Em Python, o código a = a + 1dentro de uma função realmente cria uma cópia da variável alocal na função. E essa variável local permanece apenas até o final da função e é excluída no final da função em execução.

A variante 2, a[:]cria a visão do array original, é como uma referência ao subconjunto de elementos do array original, apenas :é vista para todo o array, atribuindo a esta visão modifica o array original. A visualização modificável também é criada por fatias como a[1:3]e indexação como a[2]ou a[[1,2]].

Escrever a[:] = some_operation(a)é provavelmente a maneira mais intuitiva e rápida de devolver uma acópia modificada / transformada de a.

As variantes 3, 4, 5 são outras maneiras sofisticadas de atribuir a expressão do lado direito de volta ao array a.