こんにちは(@t_kun_kamakiri)。
今回は、「参照渡し」と「値渡し」というのを理解していきたいと思います。
基本的な内容はこちらのサイトにそってやっていきます。
この記事ではこんな人を対象にしています。
- Pythonを使い始めたけどどう使うかわからない
- 流体の数値計算をはじめて勉強する人
☟前回の記事がまだの人はこちらから
「参照渡し」と「値渡し」について解説をします。
「参照渡し」とか「値渡し」とか名前だけで、うわっめんどくさい内容だなって思うかもしれません。
質問1:「a = 5」を代入
めちゃくちゃ簡単なところからはじめます。
1 2 3 |
a = 5 print('a=',a) |
1 |
a= 5 |
当たり前の結果が返ってきますよね。
質問2:「b = a」は?
では、次の場合はどうなるでしょうか?
「a = 5」としておいて、「b」に「a」を代入しています。
1 2 3 4 5 |
a =5 b = a print('a=',a) print('b=', b) |
【結果】
1 2 |
a= 5 b= 5 |
これも思った通りの結果が返ってきたのではないでしょうか?
質問3:途中で「b = 10」にする
では、これはどうでしょうか?
「a = 5」と始めしておいて、それを「b = a」とします。
そして途中で「b = 10」と値を変更します。
1 2 3 4 5 6 7 8 9 10 11 |
a =5 b = a print('a=',a) print('b=', b) b = 10 print('\n↓変更後\n') print('a=',a) print('b=', b) |
質問の意図は、はじめの「a,bの値」とb変更後の「a,b」の値はどうなっているのか?です。
【結果】
1 2 3 4 5 6 7 |
a= 5 b= 5 ↓変更後 a= 5 b= 10 |
これもあまり難しい内容ではなかったかもしれませんね。
「b」の値だけを変更したから、b変更後のbの値だけが変更されています。
当たり前と言えばそれまでですが、実は配列にしたときにちゃんと理解しておかないと「あれ?」ってなるので解説を加えます。
「変数」というのは値を入れておくための箱のようなもので、そこにはアドレス(番地)が割り振られています。
- 「a = 5」としたときの変数に対するアドレスは決まっています。
そこで「b = a」とすると「b」は「a」と同じアドレスを使うことになります。 - しかし、「b = 10」とすると、変数が再定義されて違うアドレスを用意して値を箱に放り込みます。
こうなっているんですよね。
というわけでアドレスを確認してみましょう。
idを確認することになるので、以下のように書いて確認をします。
1 2 3 4 5 6 7 8 9 10 11 |
a = 5 b = a print('a=',id(a)) print('b=', id(b)) b = 10 print('\n↓変更後\n') print('a=',id(a)) print('b=', id(b)) |
【結果】
1 2 3 4 5 6 7 |
a= 10914624 b= 10914624 ↓変更後 a= 10914624 b= 10914784 |
変更前は「a,b」ともに同じidだったのに、変更後には「b」のidだけが変わっています。
なるほど「b = 10」と変数を定義しなおすと、違う箱を用意して値を入れるのか・・・・・
というノリで配列にをやると「あれ?」ってなります。
質問3:「参照渡し」について
まずは、☟こちらのコードを書いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
import numpy as np data_x = [1,2,3,4,5] data_y = [10,20,30,40,50] x = np.array(data_x) y = np.array(data_y) z = y print(x) print(y) print(z) |
【結果】
1 2 3 |
[1 2 3 4 5] [10 20 30 40 50] [10 20 30 40 50] |
そりゃーそうなるよなっていう結果ですね。
では、ここでyの要素の一部を「y[0] = 100」として変更してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import numpy as np # 参照渡し data_x = [1,2,3,4,5] data_y = [10,20,30,40,50] x = np.array(data_x) y = np.array(data_y) z = y print('x=',x) print('y=',y) print('z=',z) print('\n↓変更後\n') y[0] = 100 print('x=',x) print('y=',y) print('z=',z) |
【結果】
1 2 3 4 5 6 7 8 9 |
x= [1 2 3 4 5] y= [10 20 30 40 50] z= [10 20 30 40 50] ↓変更後 x= [1 2 3 4 5] y= [100 20 30 40 50] z= [100 20 30 40 50] |
「あれ?y[0]だけ変えたのに、z[0]も変わってしまった・・・・」ってことになりました。
落ち着いて、アドレス(id)を確認してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 参照渡し import numpy as np data_x = [1,2,3,4,5] data_y = [10,20,30,40,50] x = np.array(data_x) y = np.array(data_y) z = y print('x',id(x)) print('y',id(y)) print('z',id(z)) y[0] = 100 print('\n↓変更後\n') print('x',id(x)) print('y',id(y)) print('z',id(z)) |
【結果】
1 2 3 4 5 6 7 8 9 |
x 140007511214000 y 140007511212080 z 140007511212080 ↓変更後 x 140007511214000 y 140007511212080 z 140007511212080 |
結果を見るとどうやらこういうことみたいです。
- 「z = y」とすると、変数を再定義しているのではなく「yと同じアドレス内の要素」を受け取りに行っています。
- 「y[0] = 100」とするとyも変数を再定義しているのではなくて「アドレス内の要素」を変更しているだけです。
ということになります。
これを参照渡しと呼びます。
言葉はわかりにくいのですが、
質問4:「値渡し」について
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 値渡し import numpy as np data_x = [1,2,3,4,5] data_y = [10,20,30,40,50] x = np.array(data_x) y = np.array(data_y) z = y.copy() print('x=',x) print('y=',y) print('z=',z) print('\n↓変更後\n') y[0] = 100 print('x=',x) print('y=',y) print('z=',z) |
【結果】
1 2 3 4 5 6 7 8 9 |
x= [1 2 3 4 5] y= [10 20 30 40 50] z= [10 20 30 40 50] ↓変更後 x= [1 2 3 4 5] y= [100 20 30 40 50] z= [10 20 30 40 50] |
「y[0] = 100」となっていますが、z[0]の値は変更を受けていないですよね。
これを理解するためにアドレス(id)を見てみれば理解ができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 値渡し import numpy as np data_x = [1,2,3,4,5] data_y = [10,20,30,40,50] x = np.array(data_x) y = np.array(data_y) z = y.copy() print('x',id(x)) print('y',id(y)) print('z',id(z)) y[0] = 100 print('\n↓変更後\n') print('x',id(x)) print('y',id(y)) print('z',id(z)) |
【結果】
1 2 3 4 5 6 7 8 9 |
x 140007511212080 y 140007511117696 z 140007511138096 ↓変更後 x 140007511212080 y 140007511117696 z 140007511138096 |
これを見ると、「z = y.copy()」としたときに参照渡しと違って、違うアドレスを用意して内容をコピーしていることがわかります。
つまり、絵にしてみると☟こんな感じ。
- 「z = y.copy()」とすると、変数を再定義していて「yとは違うアドレスを用意」して内容をコピーしています。
- 「y[0] = 100」とするとyも変数を再定義しているのではなくて「アドレス内の要素」を変更しているだけです。
- 「z[0]」の値はyのアドレスとは関係がないので変更を受けていない。
ということになります。
これを値渡しと呼びます。
言葉はわかりにくいのですが、
まとめ
本日の内容は、「参照渡し」と「値渡し」という内容でした。
ちょっと理解しにくい部分ではありますが、
とこのように覚えておくと良いでしょう。
では、また(^^)/
Pythonの完全初心者は書籍で学ぶとよい
Python自体が不安だという方は、こちらの書籍から勉強しても良いかも知れません。
☟こちらの本がPython初心者が挫折することなく勉強できる本です。
(本記事のようのPython使用環境と異なりますが、とてもわかりやすいので全く問題ありません)