知ったつもりでは怖いPython。「参照渡し」「浅いコピー」「深いコピー」

Python制覇か?(あとは必要になったら覚えよう)

私はあまり深い機能は使わないので、以下の(1)~(4)の基本コマンドだけ調べて、少し長めのプログラムを組んでみました。(コードは秘密) だいたい、どの言語でも以下の(1)~(4)がわかれば、プログラムの心臓部はかけると思います。

(1) if文による条件分岐
(2) for文による繰り返し
(3) 配列(リスト)
(4) 関数、クラス

「配列はリストを使うんだな~。あれ、多次元配列の宣言、面倒。」

「きちんとプログラムかかないと、入力と出力があまり明確じゃないな~。後で読み返すのが大変そう。」

「細かい書式を無視すればグラフの出力が簡単!変数の内容を見たいときは便利だな~!」

などと考えながら、プログラム完成。

よし、Python制覇!(あとは、必要ななったら覚えよう)

しかし、舌も乾かないうちにPython制覇は取り消し!

Python制覇宣言の取り消し理由

基本的な機能を理解するだけで十分に使える言語だと思います。あまり、難しいことは考えず、自分が必要な部分から(のみ)使ったのでよいと思います。でも、私の場合、以下の(1)(2)の理由から、Python制覇宣言を取り下げて、Pythonの基本的な事項をもう少し勉強をしてみようと思います。

わかったつもりでは、書籍を読むのに時間がかかる。

a, b=1, 2という衝撃的な代入法や、lambda式など便利な機能がたくさんあり、例えばディープラーニングの書籍には、これらの機能が使われています。
本を読み進めるとき、a, b=1, 2ならば「代入してるんだな」とわかりますが、lambda式だと調べなければわかりません。これが面倒くさい!しかも、知識が浅いので。どれがコマンド名でどれが関数名なのかがピンとこない。

自分で組むなら、a, b=1, 2 は、a=1   b=2でよいし、lambda式も関数を使えばいいから困らないけど、もっと書籍をサラサラ読めるようになりた~い。

わかったつもりでは、怖いミスをしそう。

以下のコードを実行すると出力はb = [2]となります。bにaを代入し、コピー元(a)を変えるとコピー先(b)も変わってしまうのです。怖すぎると思いませんか?
私が作ったプログラムも、チェックしなければ間違えてるかもしれない。

コードa>

a = [1]
b = a
a[0] = 2
print('b = ', b)

出力a>

b =  [2]

 

自分のコードをチェックすると、古典的な言語しか知らない私は以下の様な書き方をしていたので問題はありませんでした。
よく考えてみれば、上の「コードa」はPythonでは当たり前の表記でも、「私は」ExcelのVBAでb = aの様な代入は使っていません。そもそも、私はこの様なミスを考えなければならないレベルにすら到達していなかったわけです。
でも、Pythonの良さを引き出した短いコードを作成しようとすると、大けがをする可能性がありますので注意が必要です。

コードb>

a = [0] #VBAの配列aの宣言に相当
b = [0] #VBAの配列bの宣言に相当
a[0] = 1 
b[0] = a[0]
a[0] = 2
print('b = ', b)

出力b>

b =  [1]

 

代入では「参照渡し」「浅いコピー」「深いコピー」の違いを理解する必要があります。ちなみに「コードa」のb=aは「参照渡し」です。こんな違いがあるのは私のような初心者には恐怖です。代入するたびに、どのコピーなのかを気にしなければならないのです。こんなことでは、安心してコードを記述することができません。

しかし、この「参照渡し」「浅いコピー」「深いコピー」という考え方は、JAVAにもあります。そして、ExcelのVBAでも、動的配列にコピーすれば、「深いコピー」ができるらしいのです。つまり、別にPythonが悪いわけではないのです。単に私の知識不足なのです。

やはり、つまみ食いではなく、この機会に基本事項ぐらいはさらりと、勉強しないといけませんわね!おほほほほ~。

参考記事:
「参照渡し」「浅いコピー」「深いコピー」に関する記事を集めました。まず、それぞれががどんな結果になるかを、理屈抜きで知りたい方は、記事c)を参考にしてください。

a) コンピューターの変数の記憶には、参照先のアドレスが利用される。

b) 変更可能体と変更不能体はidに注目。浅いコピーなどの理解に役立つ。

c) 「参照渡し」「浅いコピー」「深いコピー」まずは、理屈抜きで覚えよう。