Python♪NumPyの「参照渡し」と「コピー」を覚えよう。JuneホームPython♪の学習とホームページ作成のブログPython♪NumPyの「参照渡し」と「コピー」を覚えよう。2018.07.22リストの「参照渡し」「浅いコピー」「深いコピー」とNumPyの配列の「参照渡し」「コピー」とは、コンピューターの内部でのメモリーの扱いも実行のしかたも全然違います。これを混同してしまうと大変なことになります。ここでは、NumPyの配列の「参照渡し」「コピー」について整理します。NumPy配列のデータ型がオブジェクト型の場合は説明の対象から外します。リストの「参照渡し」「浅いコピー」「深いコピー」は、以下の記事で紹介しています。できれば、この記事を読む前に目を通してください。参考記事:「参照渡し」「浅いコピー」「深いコピー」まずは、理屈抜きで覚えよう。どのようにコピーすればよいのか結果だけを知りたい方は、この記事の最後のまとめ(リストとNumPy配列のコピーの比較)だけをご覧ください。リストとNumPyの配列の「参照渡し」「浅いコピー」「深いコピー」「NumPyのコピー」等を網羅した比較表です。NumPyの要素のidがもっと変になった3.NumPyの配列の「参照渡し」「コピー」のやり方を覚えよう。リスト:代入式の左辺にスライスを用いたコピー3.まとめ(リストとNumPy配列のコピーの比較)1.リストとNumPyの配列はメモリ-の扱いが違うリストとNumPyの配列は、メモリーの扱いが異なるため、リストの考え方は通用しません。どのようにメモリーの扱いが違うかを簡単に(?)紹介したいと思います。リストではアドレスの参照の仕方を勉強した方がおもしろいと思いますが、NumPyの配列では、あまり、深みにはまらない方がよいのではないかと思います。リストの「参照渡し」のidコード01は、3行目で参照渡し(b=a)を行っています。2]のアドレスをbに渡すため、aとbのidは同じになります。このリストオブジェクトには要素である整数1、整数2のアドレスが記憶されています。aとbは同じリストオブジェクトを参照しているので、当然、a[0]とb[0]のidも同じになり、a[0]とb[0]は同じアドレスに記憶された整数1を参照します。次に、6行目でa[0]に3を代入した後のidを見てみましょう。bのidは代入前と同じです。同じリストオブジェクトを参照しています。b[0]は代入前とは違うidを参照しています。3では、要素の参照先を元の整数1とは別の場所に記憶した整数3に変更します。代入前と代入後で、id(a[0])やid(b[0])は変化します。aもbも同じリストオブジェクトを参照しているので、aが参照しているリストオブジェクトの内容が変更されれば、bの内容も連動して変更されます。代入後のid(a[0])とid(b[0])は互いに同じidになります。#aとbの要素のidも同じ。#要素の変更→aとbは連動する。#aとbのidは同じ#以下、aとbの要素のidは同じですが要素の変更前とは変化している。リストの「深いコピー」のidコード02は、4行目で深いコピー(b=copy.deepcopy(a))を行います。深いコピーではリストオブジェクトを共有するのではなく、全く別の新しいリストオブジェクトを作成します。したがって、深いコピー後の、aとbのidは互いに異なります。理解しにくいのは出力を見ると、深いコピー後のa[0]とb[0]が互いに同じidになっています。これは、わざわざ同じ整数要素を別の場所にも記憶させる必要はないというPython内部での節約術です。同じアドレスの整数を共有すると、要素の変更が連動してしまうのではないかと思うかもしれませんが、要素が整数やタプルのような変更不能対(イミュータブル)の場合は問題にはなりません。7行目でa[0]に3を代入するときに、もし、元の整数1が記憶されているアドレスに3を上書きすると変更が連動してしまいます。実際には代入する整数3は、整数1とは違うアドレスに記憶されます。整数1を書き換えるのではなく、整数1は放置し、全く新しい場所に整数3を再定義するのです。a[0]に3を代入しても、b[0]は連動して変化しないのです。7行目でa[0]に3を代入した後のidを見てみましょう。b[0]のidは代入前と同じですが、3を代入したa[0]は代入前とidが異なります。要素がリストのような変更可能体(ミュータブル)の場合には、idが同じだと深いコピーにならないので、値を共有せずidが変化します。それぞれの変数が互いに独立を保てる場合だけPythonが節約術を行使するのです。この様に実際には内部で少し複雑な処理がなされている場合があります。考え方としては、深いコピーでは全く違うリストオブジェクトを作成すると考えておいた方が理解しやすいと思います。重要なことは深いコピーでは変数a、bは互いに独立しており、片方の要素を変更しても他方が連動しないということです。#a[0]とb[0]のidは同じ。#要素の変更→aとbは連動しない。#a[0]とb[0]のidは同じ。13468584642.NumPyの要素のidは変NumPyのidを調べてみたのですが、要素のidについては、変な結果になることが分かりました。内容が趣味の世界になるので、記事をクリックで表示する形式にしました。興味のあるかただけ開いてください。ここで知っておかなければならないのは、リストとNumPyの配列は、アドレスの参照方法がまったく異なり、リストの時の考え方は通用しないと言うことです。NumPyの配列は、リストと比較し、行列計算が異常に速く科学技術計算にも耐えられる速度を実現できます。その速度を実現するためにリストにはない制約もあります。1各要素のデータの型は同じでなければならない。2多次元配列にする場合、各次元の要素数は同じでなくてはならない。3メモリー上のデータの保存では連続したメモリー領域を確保している。4原則、最初に決めた配列の大きさを途中で変えられない。x=numpy.append(x,y)で追加できなくもないが、メモリーを別の領域に確保しなおすため、リストのx.append(y)よりも遅い。これらの制約や、内部での計算方法の様々な工夫によりNumPyの配列は、超スピードの行列計算が可能になっています。メモリーの参照の仕方が難しいのは仕方がないのかもしれません。NumPyの配列の「参照渡し」のid記事の表示・非表示の切り替え※ブラウザによっては最初から表示されてしまいます。参照渡し直後は、aとbのidは互いに同じです。a[0]とb[0]のidも互いに同じになっています。ここまでは、リストと同じです。次に、7行目でa[0]に3を代入した後のidを見てみましょう。b[0]のidもお互いに同じです。これも、リストと同じです。b[0]のidが同じだったのに対して、NumPyの配列では代入前後でidが変化しません。この様に、リストとNumPy配列で、メモリーの参照の仕方が異なることが分かります。#a[0]とb[0]のidは同じ。#a[0]とb[0]のidは同じ。NumPyの配列の「コピー」のid記事の表示・非表示の切り替え※ブラウザによっては最初から表示されてしまいます。Chrome推奨)コード04は、4行目でNumPyで用意されたコピー(b=a.copy())を行います。コピー直後、aとbのidはそれぞれ異なります。a[0]とb[0]のidは互いに同じです。ここまではリストと同じです。次に、7行目でa[0]に3を代入した後のidを見てみましょう。bのidは代入前と同じです。b[0]のidはどちらも代入前と変化しないのです。1を示しているのです。私が勉強不足なだけなのですが、NumPyのアドレスの参照方法については、あまり深追いしない方がよいのではないかと思いました。#a[0]とb[0]のidは同じ。#a[0]とb[0]のidは同じ。NumPyの要素のidがもっと変になった記事の表示・非表示の切り替え※ブラウザによっては最初から表示されてしまいます。Chrome推奨)コード05はもっと変な結果になりました。別に定義したNumPy配列の要素も全て同じidになりました。NumPy配列の要素のidについては参照渡しとかコピーとか関係なかったみたいです。違う変数に代入したNumPy配列であっても、要素は同じオブジェクトとして一括管理しているということなのでしょうか?やはり、私ごときがこれ以上の深追いは禁物でした。22131565300003.NumPyの配列の「参照渡し」「コピー」のやり方を覚えよう。以下、NumPy配列の「参照渡し」と「コピー」のやり方を紹介します。理屈を知ろうとすると難しいですが、やり方は簡単です。リストの「浅いコピー」に相当する者はなく、すべて「深いコピー」になります。NumPyの配列の「参照渡し」NumPyの配列の「参照渡し」は3通りあります。a」と直接代入する方法です。2つ目の方法は10行目、15行目のようにスライスを使う方法です。b=a.view()」とする方法です。「参照渡し」ですので、片方の変数の要素を変更すると、他方の変数の要素も連動して変更されます。ここで注意しなければならないのは、リストでスライスを用いた場合は「浅いコピー」でしたが、NumPyでは「参照渡し」になることです。ように変数を再定義した場合は、それぞれ独立した変数となります。「変数の再定義」は、現在のデータを消して上書きするのではなく、現在の記憶場所を放置し、別の記憶場所に定義し直します。NumPyの配列には「浅いコピー」はないNumPyの配列に「浅いコピー」はありません。リストの「深いコピー」に相当するコピーだけが存在し、それぞれの変数は完全に独立しています。a.copy()(書式1)とb=numpy.copy(a)(書式2)の2種類です。いずれもNumPyで用意されたメソッドであり、リストのcopy.copy()とは異なります。copy.deepcopy(a)を使用することはできます。copy.deepcopy(a)は、それぞれ完全に独立した変数となりますので、あえて、リストの表記を使う必要はないと思います。NumPy:代入式の左辺にスライスを用いたコピーPythonの配列では、コード09のように代入式の左辺にスライスを用いたコピー方法もあります。これは今までのように、定義されていない変数に代入する方法ではなく、すでにNumPyの配列を代入された変数に値をコピーする方法です。このとき、代入する側の配列の形と代入される側の配列の形は同じでなければなりません。代入される側(左辺)の配列の参照先は変わらないまま、右辺の要素をコピーするので、代入前に左辺の変数が別の変数と連動する状況であれば代入後も連動し、代入される前に完全に独立した変数であれば代入後も完全に独立した変数のままです。#aがbを参照している状態なら、参照している状態のまま。#aとbがそれぞれ独立した変数なら、独立した変数のまま。#aがbを参照している状態なら、参照している状態のまま。#aとbがそれぞれ独立した変数なら、独立した変数のまま。リスト:代入式の左辺にスライスを用いたコピーリストの場合左辺にスライスを用いたコピーがどうなるか調べてみましょう。結果はコード10のようになりました。a[:]=bでも、a=b[:]と同じように浅いコピーができました。a=b[:]と違い、定義されていない変数に代入することはできません。NumPyの配列と異なり、配列の大きさが異なる場合でも代入することができます。#リストの一番上の参照を渡す→浅いコピーと同じ。#リストの一番上の参照を渡す→浅いコピーと同じ。[]print('代入前')print(a)print(b)#リストの配列の大きさが違っても代入できる。#一番上の参照を渡す→浅いコピーと同じ。[2]]3.まとめ(リストとNumPy配列のコピーの比較)リストとNumPy配列の比較は下表となります。解説しましたが、NumPy配列はリストの「浅いコピー」に相当するコピーがないため、リストよりは覚えやすいと思います。リストとNumPy配列はメモリーへの記憶方法などが全く異なるので、リストのコピー方法の考え方はまったく参考にならないことに注意していただければo.k.です。NumPy配列のデータ型がオブジェクト型の場合は対象から外します。オブジェクト型の場合は以下の表とは違う結果になります。オブジェクト型を使うぐらいならリストを使う方がよいと思います。表中の推奨しないとは「あえてcopyをimportしてまで使う必要もない」との意味です。June関連記事PythonPyrhon♪リストのインデックス指定とスライスの例題ゆうちゃんとのPythonの勉強もリストのスライスを覚えるところまで進みました。スライスはリスト操作において大変便利な機能ですのでしっかりと覚えましょう。Pythonのチュートリアルの図は増分がマイナスの時には使えないので注意しまし...PythonPyrhon♪リストのインデックス指定とスライス。stepが負のときは注意!スライスは要素の一部を指定できるだけでなく、逆順に並び替えたりすることも出来ます。リストを扱うときに大変便利な機能ですので使い方を整理したいと思います。stepがマイナスのときの範囲指定の方法はチュートリアルの図では間違えてしまいます...PythonPython♪ディレクトリ、カレントディレクトリ、絶対パス、相対パスディレクトリ、ルートディレクトリ、カレントディレクトリ、絶対パス、相対パス。こんなことは、Windowsでは気にする必要がありません。プログラムを組んでいると、時々、その知識が必要な時があります。ここでは、絶対パスと相対パスを使って...PythonPythonの環境整備Pythonの環境を整備するためには、Pythonだけをインストールすればよい訳ではありません。豊富な外部ライブラリを利用してこそのPythonの本領を発揮するのですが、これらは、Pythonをインストール後、別にインストールする必要があ...PythonPython♪format()メソッドの基本的な使い方str.format()メソッドでは、キーワードによる指定、表示幅の指定などが可能ですが、どのように組み合わせて記述すればよいのでしょうか。改行のように通常の文字列では表現できないものも「\n」といった文字列で記述することができます。「\n」のような特...Python♪「参照渡し」「浅いコピー」「深いコピー」まずは理屈抜きで覚えよう。Python♪関数のスコープは3層入れ子構造(ネスト)の具体例で理解しよう。Studioが遅いときの対策2020.01.11Kotlin♪環境設定「HAXMがインストールされていません」2020.01.052020.01.08Python♪FEM:部材座標系の要素剛性マトリクス2020.01.04Kotlin♪スマホアプリの言語は、Kotlin、Java、C#、Dart?2020.01.012020.01.13スポンサーリンクスポンサーリンク。