KNIMEST’s diary

KNIME使いがPythonも使いたくて勉強中

【Python学習帳】016_浅いコピーと深いコピー

初学者を対象としている京都大学の無料Python教材の学習中です。
「プログラミング演習 Python 2021」
Version2021_10_08_01.pdf

hdl.handle.net

CC-BY-NC-NDライセンスに従って引用します。

本教材での到達目標:

Python によるプログラムの実行についての基本操作ができるようになる.
Python プログラムを構成する基本的要素の機能と書式について説明し,例題を用いて実行例を構成できるようになる.
Python を用いて簡単なプログラムを自ら設計,実装,テストできるようになる.

第4章の勉強中です。

knimest.hatenablog.com

今回は浅いコピーと深いコピーの違いを学びます。

そもそもの大切な考え方として

Python では変数はデータそのものを持つのではなく,「データの所在」を持っています.

それを踏まえてリストオブジェクトについて値の変更をすると何が起きるのかを以下で見ていきます。

「データの所在」すなわちidを観察します。

 

まず

リストはその要素などの変更を許す「ミュータブル」なオブジェクトとして扱われます.このため,同じリストへの参照をもつ2つの変数(a, b) があるとき,a や b の要素への変更は別の変数の指す内容にも反映されてしまうのです

ということでした。
では、aがリスト型で、かつ要素もまたリスト型であった場合に、copyメソッドでbを作ってみます。

a = [[1, 2], [3, 4]]
b = a.copy()

そしてbの要素に下記の各操作をしたらどうなるかidの変化も一緒に観察してみます。

b.append([5, 6])

b[0][0] = 0

結果は下記の通りでした。

b.append([5, 6])

を実行したら

b は a のコピーを代入したので b への append() は a とは独立に行えています.

aのコピーであるbはidが別のオブジェクトなのでそれはそうだなと思えます。

ところが

b[0][0] = 0

を実行すると、bだけではなく別idのaの[0][0]すなわち、aのリストの0番目の要素のリストの中の0番目の要素も0に変わっていますね。

これは copy() メソッドが対象となるリスト(コピー元)とは別のリスト(コピ

ー先)を用意して,コピー元の各要素について,その所在をコピー先に写し取って

いったことによります.したがって,要素がリストの場合はそのコピーが作られて

いる訳ではありません.このようなコピーを「浅いコピー (shallow copy)」と呼

び,要素までコピーを作成することを「深いコピー(deep copy)」と呼びます.

ややこしいよ…。

 

理解の助けにと

4.12 リストを可視化する

に記載の通りウェブサイトPython Tutorを体験してみました。

www.pythontutor.com

短い Python プログラムを入力して,その動作(変数の利用)を可視化してくれます.

Edit this codeを押下し、別タブで開いた下記ウィンドウにコードを入力し、Visualize Excecutionボタンを押下。

そうすると画面が切り替わり、PrevやNextボタンを使うことで、各行でどのようにオブジェクトが作られ、それぞれどこの「データの所在」すなわちidを見ているかを目で追えるようになるのです。

b = a.copy()

b.append([5, 6])

そして

b[0][0] = 0

は間違い探しのようですが、確かに[0][0]のデータが変わるのが分かります。

リストの動作を確認するのに使うと理解の助けになると思います.

とのことで、確かに便利そうだと思いました。

このサイトがどれほどの長さのコードまで可視化してくれるのかは気になりますが、今後使いたいと思いました。

 

次回はdeepcopyも使ってみようと思います。

knimest.hatenablog.com