Setiap operasi yang kita tulis sejauh ini — a + b, np.sqrt(a), a * 0.9 — mengalokasikan array baru untuk hasilnya. Pada array kecil perilaku itu tidak terasa, tetapi pada array ratusan megabita yang dioperasikan berulang kali, alokasi yang terus-menerus membebani memori dan memperlambat program. NumPy menyediakan jalur kedua: operasi in-place, yang mengubah isi buffer array yang sama tanpa membuat array baru.
Bab ini membahas dua alat in-place dan satu batasannya:
- Operator augmented:
+=,-=,*=, dan kawan-kawannya. - Parameter
outpada ufunc untuk menulis hasil ke array yang telah disiapkan. - Batasan dtype: operasi in-place tidak boleh mengubah tipe data array.
Operator augmented mengubah array langsung #
Operator augmented Python berperilaku khusus pada array NumPy: alih-alih membuat array baru, NumPy mengubah buffer array asli:
import numpy as np
stok = np.array([10, 20, 30])
stok += 5
print(stok)
stok -= 3
print(stok)
stok *= 2
print(stok)Output yang Dihasilkan:
[15 25 35]
[12 22 32]
[24 44 64]- Baris 4 (
stok += 5): setiap elemenstokditambah 5 di tempatnya. Buffer array10, 20, 30langsung menjadi15, 25, 35; tidak ada array kedua yang lahir. - Baris 6 (
stok -= 3): pengurangan in-place memakai buffer yang sama lagi. - Baris 8 (
stok *= 2): perkalian in-place; hasil akhir24, 44, 64tinggal di objekstokyang pertama.
Daftar lengkap operator augmented dan catatannya:
| Operator | Keterangan |
|---|---|
a += b | penjumlahan in-place |
a -= b | pengurangan in-place |
a *= b | perkalian in-place |
a //= b | pembagian lantai in-place |
a %= b | sisa bagi in-place |
a **= b | pangkat in-place |
a /= b | pembagian in-place; menuntut array float karena hasil / selalu float |
a = a + b dan a += b tidak sama #
Perbedaan paling penting terlihat ketika dua nama menunjuk array yang sama. Bentuk a = a + 10 membuat array baru; bentuk a += 10 mengubah buffer lama:
import numpy as np
a = np.array([1, 2, 3])
b = a
a = a + 10
print(b)
c = np.array([1, 2, 3])
d = c
c += 10
print(d)Output yang Dihasilkan:
[1 2 3]
[11 12 13]- Baris 5 (
a = a + 10): sisi kanan dihitung menjadi array baru berisi11, 12, 13, lalu namaadipindahkan menunjuk array baru itu.bmasih menunjuk array lama, sehingga masih mencetak[1 2 3]. - Baris 8 (
c += 10): tidak ada array baru; buffer yang dibagicdanddiubah langsung, sehinggadikut melihat[11 12 13].
| Ekspresi | Yang terjadi | Nama lain yang menunjuk array yang sama |
|---|---|---|
a = a + 10 | array baru dibuat; a menunjuk array baru | tidak terpengaruh |
a += 10 | buffer array lama diubah | ikut berubah |
Batasan dtype: in-place tidak mengubah tipe #
Operasi in-place wajib menampung hasil ke dtype yang sudah ada. Ketika hasil tidak muat, NumPy menolak operasi tersebut:
import numpy as np
a = np.array([1, 2, 3])
try:
a += np.array([0.5, 0.5, 0.5])
except TypeError as e:
print(type(e).__name__)
print(e)
a = a + np.array([0.5, 0.5, 0.5])
print(a)Output yang Dihasilkan:
UFuncTypeError
Cannot cast ufunc 'add' output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
[1.5 2.5 3.5]- Blok
try(baris 4-8):abertipeint64, sedangkan hasil penjumlahan dengan float bertipefloat64. Menampungfloat64ke bufferint64berarti memotong informasi, sehingga NumPy melemparUFuncTypeErrordengan aturan castingsame_kind. - Baris 9 (
a = a + ...): bentuk penugasan biasa bebas dari batasan itu karena array baru ber-dtype float64 dibuat — hasilnya[1.5 2.5 3.5].
Jika memang ingin buffer int menerima tambahan pecahan, konversikan lebih dahulu dengan a = a.astype(np.float64) — perilaku konversi dibahas pada Chapter Konversi Tipe Data.
Parameter out pada skenario hemat memori #
Parameter out pada ufunc — dikenalkan pada Chapter Fungsi Universal (ufunc) — adalah bentuk in-place yang paling fleksibel: wadah hasil berdiri sendiri, terpisah dari array masukan:
import numpy as np
total = np.zeros(3)
sumber = np.array([2.5, 1.0, 4.0])
np.multiply(sumber, 4, out=total)
print(total)Output yang Dihasilkan:
[10. 4. 16.]- Baris 3 (
total = np.zeros(3)): buffer hasil dialokasikan sekali, lebih dahulu. - Baris 5 (
np.multiply(sumber, 4, out=total)): hasil perkalian ditulis langsung ketotal; sepanjang perhitungan tidak ada array hasil baru yang dialokasikan.