NumPy: Cópias e Views
Última atualização: 2026-08-26
Charlie modificou um sub-array e descobriu que o original também havia mudado — ele gastou 2 horas depurando. Alice diz: "Verifique o atributo .base. Se base is o array original, é uma view. Na dúvida, .copy()."
Esta história destaca um problema crítico: nem todas as operações NumPy retornam arrays independentes. Entender a diferença entre views e cópias é essencial para evitar bugs sutis de modificação de dados.
1. O Mecanismo de View
(1) O Que É uma View
Uma view é outra "janela" para o array original — ela compartilha a mesma memória. Modificar uma view modifica diretamente o array original.
import numpy as np
a = np.array([1, 2, 3, 4, 5])
b = a[1:4] # fatia retorna uma view
b[0] = 999
print(a) # [ 1 999 3 4 5] original mudou!
print(b) # [999 3 4]
> **Output:** Execute o NumPy 2.x em seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem o NumPy pré-instalado — instale-o localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.
A vantagem das views é zero-copy — sem memória extra, extremamente rápido.
(2) Relação de Memória
a = np.array([10, 20, 30])
b = a[:] # view
print(a.__array_interface__['data'][0]) # endereço de dados original
print(b.__array_interface__['data'][0]) # endereço de dados da view (mesmo!)
> **Output:** Execute o NumPy 2.x em seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem o NumPy pré-instalado — instale-o localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.
Ambos apontam para o mesmo endereço inicial de memória — apenas os metadados (shape, strides) diferem.
(3) O Atributo .base
a = np.arange(12).reshape(3, 4)
b = a[0:2, 1:3] # fatia view
c = a[[0, 2]] # indexação fancy — cópia
print(b.base is a) # True — view
print(c.base is a) # False — cópia
2. Quais Operações Retornam Views vs Cópias
(1) Views (memória compartilhada, sem cópia)
| Operação | Exemplo |
|---|---|
| Fatiamento básico | a[1:5], a[1:5:2], a[:, 2:4] |
.view() |
a.view(np.float32) |
reshape |
a.reshape(3, 4) |
transpose / .T |
a.T, a.transpose(1, 0) |
ravel (geralmente) |
a.ravel() |
squeeze |
a.squeeze() |
newaxis |
a[:, np.newaxis] |
(2) Cópias (nova memória, independente)
| Operação | Exemplo |
|---|---|
.copy() |
a.copy() |
| Indexação fancy | a[[0, 2, 4]] |
| Indexação booleana | a[a > 0] |
astype |
a.astype(np.float32) |
flatten |
a.flatten() |
np.where |
np.where(a > 0, a, 0) |
▶ Exemplo
> **Output:** Execute o NumPy 2.x em seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem o NumPy pré-instalado — instale-o localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.
: Verificar view vs copy com .base (Dificuldade ⭐)
import numpy as np
a = np.arange(12).reshape(3, 4)
# Fatia básica — view
b = a[0:2]
print(f"slice base is a: {b.base is a}") # True
# Reshape — view
c = a.reshape(6, 2)
print(f"reshape base is a: {c.base is a}") # True
# Indexação fancy — cópia
d = a[[0, 2]]
print(f"fancy base is a: {d.base is a}") # False
# Indexação booleana — cópia
e = a[a > 5]
print(f"boolean base is a: {e.base is a}") # False
> **Output:** Execute o NumPy 2.x em seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem o NumPy pré-instalado — instale-o localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.
3. Tabelas Comparativas
(1) Árvore de Decisão View vs Cópia
É uma fatia básica (start:stop:step)?
├── Sim → View (memória compartilhada)
└── Não → É indexação fancy/booleana?
├── Sim → Cópia (nova memória)
└── Não → Verifique atributo .base
(2) Impacto no Desempenho
| Operação | Tempo (1M elementos) | Memória |
|---|---|---|
| View (fatia) | O(1) | Compartilhada |
| Cópia (fancy) | O(n) | Nova alocação |
| .copy() | O(n) | Nova alocação |
| astype | O(n) | Nova alocação |
▶ Exemplo: Reshape e transpose retornam views (Dificuldade ⭐⭐)
import numpy as np
a = np.arange(12).reshape(3, 4)
# Reshape retorna uma view
b = a.reshape(6, 2)
print(f"reshape base is a: {b.base is a}")
# Transpose retorna uma view
c = a.T
print(f"transpose base is a: {c.base is a}")
# Modificar a view altera o original
c[0, 0] = 999
print(f"a[0, 0] after transpose mod: {a[0, 0]}")
Output:
TEXT 📖 Somente leiturareshape base is a: True transpose base is a: True a[0, 0] after transpose mod: 999
▶ Exemplo: flatten vs ravel — cópia vs view (Dificuldade ⭐⭐)
import numpy as np
a = np.arange(12).reshape(3, 4)
# ravel geralmente retorna uma view
r = a.ravel()
print(f"ravel base is a: {r.base is a}")
# flatten sempre retorna uma cópia
f = a.flatten()
print(f"flatten base is a: {f.base is a}")
# Após transpose, ravel pode precisar copiar
t = a.T
r2 = t.ravel()
print(f"ravel of transposed base is a: {r2.base is a}")
Output:
TEXT 📖 Somente leituraravel base is a: True flatten base is a: False ravel of transposed base is a: False
❓ Perguntas Frequentes
P: Como verifico se um array é uma view de outro? R: Verifique
arr.base is original. Se True, é uma view. Searr.baseé None, ele possui seus próprios dados.
P: Posso criar uma view com um dtype diferente? R: Sim —
a.view(np.float32)reinterpreta os mesmos bytes como um tipo diferente. Isso é perigoso e raramente necessário. Useastypepara uma cópia segura com conversão.
P: Por que ravel às vezes retorna uma cópia? R: ravel retorna uma view apenas se o array for contíguo na memória. Após operações como transpose, o array pode ser não-contíguo, e ravel recorre a uma cópia.
P: Quando devo usar .copy()? R: (1) Quando você vai modificar um sub-array e não quer afetar o original, (2) quando precisa de um array contíguo para uma operação em nível C, (3) quando quer quebrar o link de memória explicitamente.
📖 Resumo
- Views compartilham memória com o array original; modificá-las modifica o original
arr.base is original— True significa view, False significa independente- Fatiamento básico, reshape, transpose, ravel: retornam views
- Indexação fancy, indexação booleana, flatten, astype: retornam cópias
- Views são rápidas (O(1)) mas perigosas; cópias são seguras mas custam memória
- Na dúvida, use
.copy()explicitamente
📝 Exercícios
-
Básico (Dificuldade ⭐): Crie um array 1D de 10 elementos. Crie uma fatia, uma indexação fancy e uma seleção por máscara booleana. Para cada uma, verifique se modificar o resultado altera o original.
-
Intermediário (Dificuldade ⭐⭐): Crie um array 3x4, pegue uma fatia 2x2 e modifique-a. Observe o original mudando. Agora use
.copy()e repita — confirme que o original permanece inalterado. -
Desafio (Dificuldade ⭐⭐⭐): Crie um array 3D, transponha-o, depois tente fazer reshape do resultado. Verifique se o reshape retorna uma view (use
.base). Explique por quê ou por quê não.