Pythonの変数について2

python&pointer Python

書きながら、Python における変数って箱というより矢印じゃね?と思ったので、Pythonと矢印のイメージにぴったりなこちらの絵をいらすとやさんから。
いつも多彩なイラストありがとうございます。感謝。

まずは前回の「むむ、なんで??」に対する回答をチコちゃん風に。

何故こんな変数に代入した値が変わってしまうのか? それは

「ListがMutableだから〜」

あの番組にも、言葉の意味がわかるけれど繋がりが分からない回答と、言葉の意味からわからない場合があったと思います。

今回の回答は少し分かってきた方には前者の、全く初心の方には後者の、とどちらの方でもいけるハイブリットな感じの素敵回答です。

分かっている方には当然、という点も同じ。

ちなみにこのまとめは名著“Learning python 5th edition”の情報を基にしています。
この本については後ほど。

まず一つ目のaとnの一連のコードでPythonのデータの持ち方を簡単に。

>>> a = 3
>>> n = a

>>> a
3
>>> n
3

>>> a = "sample"

>>> a
'sample'
>>> n
3

最初に変数aにメモリにint型として保存した3を割り当てる。 次に新しい変数nにaを割り当てる。

これって、皆さんの頭の中ではaの箱に3を入れ、それをnでも共有しているこんなイメージじゃ無いでしょうか。

a = n = 3

これはあながち間違ったイメージじゃ無いのですが、実はPythonは変数に変数を割り当てられない言語です。

よって、変数nはaを通して3が割り当てられるものの、このコードの後では同じメモリ領域に保存された3を別々に参照している下記のイメージが正しい。

a => 3
n => 3

そう、今回の冒頭のイラストのイメージ通り、矢印で指している(pointしている)、あくまで参照(refer)しているイメージなんです。

これはPython用語でshared referenceという考え方です。
“both variables point to the same object via their references.”
と冒頭で紹介した本の中では説明されています。

ここでaにstr型のデータ”sample”を割り当てる。

a = “sample" 

このコードで何が起こっているのか。

まず、int型のデータ「3」はimmutableなので、 a が参照しているメモリ上に置かれた「3」データを変えられません。 よって、aは新しいstr型データ“sample”をメモリに保存してそのデータを参照する様になります。

Pythonにおいて、immutableとは、一度メモリに保存されたデータが上書き出来ない様を指します。 mutableは逆ですね。一度メモリ上にデータを置いた後でそのデータ自身を変更できる様を指します。

なんとなく結論の想像がついてきましたか? 話を続けます。

先ほどのコードの結果、aは新しくメモリ上に作られた「”sample”」を参照(refer)する様になる。

もちろんint型データ「3」は残っていて、nがそのまま参照している。
結果的に、下記の様に

a = “sample”
n = 3

とそれぞれバラバラに参照しているデータを出力して来る事になります。

二つ目のpとmの例はどうでしょうか。

>>> p = [1, 2, 3]
>>> m = p

>>> p
[1, 2, 3]
>>> m
[1, 2, 3]

>>> p[2] = "sample"

>>> p
[1, 2, 'sample']
>>> m
[1, 2, 'sample']

変数pにリスト[1, 2, 3]を割り当てる = リスト[1, 2, 3]をpで参照する様にする。

次に変数mに変数pを割り当てる = 同様にpを通してリスト[1, 2, 3]をmで参照する様にする。

先ほどと同様にpythonでは変数に変数を割り当てられないので、変数mにはpを通してlist[1, 2, 3]が割り当てられるが、これが一つのメモリ領域に保存されたlist[1, 2, 3]をp、m別々に参照している状況なのも同じ。

p => [1, 2, 3]
m => [1, 2, 3]

ここで違うのは、リストはmutable という事。

p[2](list pの3番目の要素)にstrデータ”sample”を割り当てる変更をすると、このlistは直接変更されてしまいます。なぜならmutable(一度メモリ上にデータを置いた後でそのデータ自身を変更できるデータ形式)だから。

で、pとmのどちらもがその同じlistを見続ける為、どちらにとっても参照先のデータが変わっている事になり、先のコードで見た通り、 pの3番目の要素が’sample’に変わり、 mの3番目の要素も’sample’に変わります。

>>> p
[1, 2, 'sample']
>>> m
[1, 2, 'sample']


これはlist やdictionaryなどmutable なデータ型を変数から参照している場合に起きる現象です。

今後はその変数が指している(参照している)データがmutableかimmutableか意識しながらコードを書いて行かないと、思わぬ結果になってしまいますので気をつけます。

ところで、これを避けるためにはどうすれば良いか、については。。。
長くなり過ぎたので次回で記載します。

前半で触れた本がこちら”Learning Python 5th Edition” Kindle版
日本語版が出ているのは第3版までなので、最新第5版は今の所英語版のみとなっています。
これが1,650ページという、ただの本を超えた存在となっています。もはやデータの塊。
紙では目的の場所を探せない気がするので検索機能が使えるkindle版お勧めです。しかも紙版より4割安い
日本語kindle版が出ても固定レイアウトなら持て余す事必至です。
英語版の評価で下手にネット検索で寄り道するよりもこれ買っとけ、的な事言っている人が居たのでとうとう買ってしまいました。興味ある部分だけ読んで役に立つ箇所がいくつかあれば御の字と思って使い続けてみます。

コメント

タイトルとURLをコピーしました