浅いコピーと深いコピー
Pythonではミュータブルな値のコピーのために、「浅いコピー」と「深いコピー」が存在します。
ミュータブルな例を見て見ましょう。
num = [10, 20, 30] として、num を num2に代入してid番号を調べて見ます。
numもnum2も同じid番号になります。つまりミュータブルな値は同じ場所を指しています。
注意:id番号は実行するごとに変わります。実際には下のコードのid番号と違ってきます。
num = [10, 20, 30] num2 = num print('num =', id(num), 'num2 =', id(num2)) print('num2の値',num2)
結果
num = 139706031453704 num2 = 139706031453704
num2の値 [10, 20, 30]
浅いコピー (shallow copy)
ミュータブルなリスト値は要素の値を変更したら、上のようなコードで代入した別の変数の値も変わってしまうことが理解できましたら、ではそうならないためにはどうしたら良いかということになります。
そのときに使えるのがcopyモジュールにあるcopy()になります。
copy()を使用するとリストの値をコピーして違うidに保存することができます。
このようなコピーの方法を浅いコピー (shallow copy)といいます。
注意:copyは標準モジュールではありませんので、予めcopyモジュールをインポートしておく必要があります。
import copy my_list = [1, 2, 3] print(id(my_list),my_list) my_list2 = copy.copy(my_list) print(id(my_list2),my_list2) my_list2.append(4) print(id(my_list),my_list) print(id(my_list2),my_list2)
結果
139661263882504 [1, 2, 3]
139661263881288 [1, 2, 3]
139661263882504 [1, 2, 3]
139661263881288 [1, 2, 3, 4]
これで、先ほどのような問題は起こらなくなりました。
深いコピー (deep copy)
次に要素の中のひとつに整数ではなく、リストの要素を入れて見ます。
このような場合に浅いコピーでは問題が起こります。
実は、copy()を使うと次の図ようなコピーが行われます。
確かにリストの値はコピーされて、my_list1とmy_list2では別のid番号となります。
しかし、リストの中にある要素の値は実はまた個別のid番号を参照しているのです。
そして、その値がイミュータブルなものなら値を変更すると新たな場所にその変更された値が入りid番号は変更されます。
そのため、my_list1とmy_list2の値は別々の値になります。
ところが、要素の値がミュータブルな値だったらここでもid番号は変わらずmy_list1とmy_list2両方が指すid番号で管理されることになります。従って、my_list1とmy_list2の値はお互いに同じ値になってしまうのです。
それを防止するために、deepcopy()が存在します。deepcopy()を使用すると要素の値が何でも問題は起こらなくなります。
このように、deepcopy()を使ったコピーのことを「深いコピー」といいます。
import copy my_list = [1, 2, [3, 4]] print(id(my_list),my_list) my_list2 = copy.deepcopy(my_list) print(id(my_list2),my_list2) my_list2[2][0] = 9 print(id(my_list),my_list) print(id(my_list2),my_list2)
表示
139661273909704 [1, 2, [3, 4]]
139661263530888 [1, 2, [3, 4]]
139661273909704 [1, 2, [3, 4]]
139661263530888 [1, 2, [9, 4]]
参考になった書籍
プログラミングを少しでも経験がありPython の文法を学習する場合は、「入門 Python 3」が良いと思います。長く使えます。
「退屈なことはPython にやらせよう」はオブジェクト指向の解説がないです。代わりにPythonを使った便利な実例が初心者には嬉しい内容です。正規表現から、簡単なスクレイピング 、画像操作などあります。ただし、中級者以上には少し物足りないかもしれません。
サンプルのダウンロード
ここでダウンロードする「BMI1.ipynb」ファイルは、この動画で使用したものです。
Python入門一覧
- Python入門 クラスの継承とオーバーライド(動画あり)
- Python入門 オブジェクト指向について、クラスの作り方(動画あり)
- Python入門 lambda関数の使い方、map関数の使い方(動画あり)
- Python入門 位置引数、キーワード引数、デフォルト引数、便利な引数の使い方(動画あり)
- Python入門 グローバル変数とローカル変数(動画あり)
- Python入門 モジュールのインポートとrandomモジュール(動画あり)
- Python入門 関数の定義方法(動画あり)
- Python入門 内包表記(動画あり)
- Python入門 zip関数(動画あり)
- Python入門 for in文の活用(動画あり)
- Python入門 for in文の基本(動画あり)
- Python入門 三項演算子(動画あり)
- Python入門 if文の使い方2 while文の使い方(動画あり)
- Python入門 if文の使い方(動画あり)
- Python入門 浅いコピーと深いコピー(動画あり)
- Python入門 参照渡し(動画あり)
- Python入門 集合(動画あり)
- Python 入門 辞書(動画あり)
- Python 入門 タプルについて(動画あり)
- Python入門 リストのメソッド(動画あり)
- Python入門 リストのスライス(動画あり)
- Python入門 リスト
- Python入門 BMI課題 (動画あり)
- Python入門 文字列の連結とフォーマット1(動画あり)
- Python入門 文字列のフォーマット2(動画あり)
- Python入門 エスケープと型変換とinput()の使い方(動画あり)
- Python入門 pep8(動画あり)
- Python入門 変数の練習(動画あり)
- Python入門 変数(動画あり)
- Python入門 文字列(動画あり)
- Python入門 演算子(動画あり)
- Python入門 Python をはじめよう! (動画あり)
コメントを投稿するにはログインしてください。