Closed3
Pythonにおけるコロンを使ったインプレース操作について

変数a
と同じ参照先を持っていた変数b
に新しいリストを代入すると、b
の参照先が変更されるので、変数a
は変更前と同じになります。
a = [1, 2, 3]
b = a
print("id(a): ", id(a))
print("id(b): ", id(b))
print("="*50)
b = [100, 200, 300]
print("a: ", a) # 出力: [1, 2, 3]
print("id(a): ", id(a))
print("id(b): ", id(b))
出力例
id(a): 138318302100096
id(b): 138318302100096
==================================================
a: [1, 2, 3]
id(a): 138318302100096
id(b): 138318301143424
一方で、[:]
を使って新しいリストを代入すると、既存のオブジェクト自体の中身を直接変更することになるので、変数b
はa
と同じ参照先のままで、リストの内容の変更も反映されます。
a = [1, 2, 3]
b = a
print("id(a): ", id(a))
print("id(b): ", id(b))
print("="*50)
b[:] = [100, 200, 300] # インプレース操作
print("a: ", a) # 出力: [100, 200, 300]
print("id(a): ", id(a))
print("id(b): ", id(b)) # a と同じ
出力例
id(a): 138318299044288
id(b): 138318299044288
==================================================
a: [100, 200, 300]
id(a): 138318299044288
id(b): 138318299044288
このように、元々あるオブジェクト自体を直接変更することをインプレース(in-place)操作といい、Pythonでは[:]
を使うことで元のオブジェクトの内容を上書きすることができます。

オブジェクトはそのままにして、中身だけを他のリストで上書きしたいときにもインプレース操作を使用できます。
a = [1, 2, 3]
b = [4, 5, 6]
print("id(a): ", id(a))
print("id(b): ", id(b))
print("="*50)
a[:] = b # a の中身を b で上書き(a 自体は同じオブジェクト)
print("a: ", a) # [4, 5, 6]
print("id(a): ", id(a)) # 元のオブジェクトのまま
print("id(b): ", id(b))
出力例
id(a): 138318299795712
id(b): 138318299791616
==================================================
a: [4, 5, 6]
id(a): 138318299795712
id(b): 138318299791616

list
とnumpy.ndarray
でスライス時の挙動が異なる場合
list
のスライスは常に新しいオブジェクトを生成します。
a = [1, 2, 3]
b = [4, 5, 6]
b = a[:] # スライス表記でlistのコピーを渡すことになる
print("a: ", a)
print("b: ", b)
print("id(a): ", id(a))
print("id(b): ", id(b))
a[0] = 100
print("a: ", a)
print("b: ", b)
a: [1, 2, 3]
b: [1, 2, 3]
id(a): 138318290623104
id(b): 138318286371392
a: [100, 2, 3]
b: [1, 2, 3]
一方、numpy.ndarrayでスライス表記を用いてb = a[:]
と記述すると、ビュー(view)として新しいオブジェクトを返します。a
とb
は異なるPythonオブジェクトなのでid()
は異なっていますが、使用しているメモリ領域が同じなので、a
とb
両方に変更が反映されます。numpy.ndarray.ctypes.data
で使用しているメモリ領域のポインタを調べてみると、a
とb
で等しいことが分かります。
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
b = a[:]
print("a: ", a)
print("b: ", b)
print("id(a): ", id(a))
print("id(b): ", id(b)) # aと異なる
print("a.ctypes.data:", a.ctypes.data)
print("b.ctypes.data:", b.ctypes.data) # 使用しているメモリ領域のポインタがaと同じ
a[0] = 100
print("a: ", a)
print("b: ", b) # 注意: bにも反映される
a: [1 2 3]
b: [1 2 3]
id(a): 138318286318704
id(b): 138318286349360
a.ctypes.data: 54965312
b.ctypes.data: 54965312
a: [100 2 3]
b: [100 2 3]
viewではなくデータをコピーしたい場合はb = a.copy()
のように記述する必要があります。
参考サイト
参照日は2025/02/01です。
- 株式会社Spot「NumPyのコピー(copy)とビュー(view)を分かりやすく解説」https://deepage.net/features/numpy-copyview.html
-
numpy.ndarray.ctypes
に関するドキュメント https://numpy.org/doc/stable/reference/generated/numpy.ndarray.ctypes.html#numpy.ndarray.ctypes
このスクラップは2025/02/01にクローズされました