6.7. Vyer och kopior¶
En vy är ett andra fönster mot samma datablock som källan. Ingen data kopieras; vyn håller en ny deskriptor (sin egen form, strides och dtype) men delar bufferten. Vyer är i praktiken gratis.
En kopia ber kameran om en ny buffert och går igenom källan för att fylla i den. Kopior kostar både tid och RAM.
De flesta av de formförändrande metoderna producerar vyer. De flesta av de datatransformerande producerar kopior. Att veta vilket som är vilket avgör om en het loop får kameran att få slut på RAM.
6.7.1. Reshape¶
reshape() returnerar en array av den begärda formen. Det totala antalet element måste vara oförändrat annars ges ValueError upphov till:
a = np.arange(12, dtype=np.uint8)
m = a.reshape((3, 4))
Resultatet är en vy – m och a delar data. Att skriva genom m[0, 0] = 99 ändrar även a[0].
Att tilldela en ny tupel till shape är en förkortning för samma operation:
a = np.arange(9)
a.shape = (3, 3)
6.7.2. Transpose¶
transpose() (eller genvägen .T) vänder på axlarna. Implementerat genom att vända på strides – ingen data flyttas:
m = np.arange(6, dtype=np.uint8).reshape((2, 3))
t = m.T # shape (3, 2), shares m's buffer
En transponerad vy går inte igenom datablocket sammanhängande. Att läsa t ovan rad för rad besöker minnespositionerna 0, 3, 1, 4, 2, 5, inte den underliggande ordningen 0, 1, 2, 3, 4, 5 som byten är utlagda i. Vanlig aritmetik och reduktioner hanterar det utmärkt – de stegar genom strides – men tobytes() kan inte, eftersom den lämnar tillbaka den underliggande bufferten direkt utan att kopiera. Byten som bufferten håller matchar inte ordningen som vyns form antyder, så metoden ger upphov till ValueError på alla icke-sammanhängande vyer. När byten behövs i den transponerade ordningen, tvinga fram en ny sammanhängande kopia först:
bytes_out = t.copy().tobytes()
6.7.3. Flatten och flat¶
flatten() returnerar en 1-D-kopia av arrayen:
f = m.flatten() # new dense 1-D ndarray
Skicka order='C' (standard) för att gå längs den sista axeln först eller order='F' för den första axeln först:
m = np.arange(6, dtype=np.uint8).reshape((2, 3))
# m = [[0, 1, 2],
# [3, 4, 5]]
m.flatten() # array([0, 1, 2, 3, 4, 5], dtype=uint8)
m.flatten(order='F') # array([0, 3, 1, 4, 2, 5], dtype=uint8)
flat är iterator-formen. Den ger varje element av en ndarray av valfri rang som skalärer, utan att allokera en platt kopia:
for x in m.flat:
print(x)
När applikationen behöver gå igenom varje element, föredra flat; när den behöver en tät 1-D-buffert att lämna till en annan funktion, använd flatten().
6.7.4. Iteration¶
Att iterera en 1-D-array ger skalärer; att iterera en array med högre rang ger (n-1)-D-vyer:
m = np.array([[0, 1, 2], [3, 4, 5]], dtype=np.uint8)
for row in m:
print(row) # array([0, 1, 2]), array([3, 4, 5])
Raderna som ges av att iterera en matris är vyer, så att modifiera dem modifierar källan.
6.7.5. Kopior¶
copy() är det explicita sättet att få en oberoende ndarray vars modifieringar inte påverkar originalet. En ny buffert allokeras och källan gås igenom in i den:
c = a.copy()
tobytes() returnerar en bytearray som delar minne med arrayens datablock. Skrivningar genom bytearray:en modifierar arrayen på plats. Ger upphov till ValueError om arrayen inte är tät (en slicad vy, en transponering, …).
tolist() returnerar innehållet som en möjligen nästlad Python-list. Användbart för att serialisera små resultat; dyrt för stora, eftersom varje element blir ett separat Python-objekt.
6.7.6. Vilka operationer som returnerar vad¶
Den fullständiga regeln:
Följande operationer returnerar vyer:
slicing –
a[1:5],a[::2],m[:, 0];indexering längs en enda axel av en array med högre rang –
m[0];att iterera en n-D-array;
reshape(), när den begärda layouten är kompatibel;transpose()/.T;asarray(), när dtype matchar.
Följande operationer returnerar kopior:
boolesk indexering –
a[mask];aritmetik –
a + b,a * 2,np.sin(a);array()– kopierar alltid, även från en annan array;
Ta till en explicit kopia endast när en oberoende buffert verkligen behövs. På en kamera med begränsat RAM är skillnaden mellan en vy och en kopia ofta skillnaden mellan kod som får plats och kod som inte gör det.