Raspberry Pi & Python 開発ブログ ☆彡

Raspberry PiとPythonの基本的な使い方をわかりやすく解説。初心者、入門者必見!!

操作しているのは、メモリのアドレスということを知る

f:id:raspberrypi:20220201162212j:plain

ブログ管理者のP.Hです!

今回は、プログラムで非常に重要なメモリのアドレスについて記載しようと思います。

初心者はこの部分を理解していない、もしくは勘違いをして理解をしている人が多いです。 また、中級者でも理解せずにコーディングしている人もいます。 この内容が理解できると、自分のコードに自信が持てるようになりますので、ぜひ読んでみてください。

それでは解説していきます。

プログラムがパソコン内部で実行される時の流れ

この内容については細かく理解する必要はありませんが、大まかな流れは知っておく必要があります。 実際には、こんなに単純ではありませんが、この程度の理解で十分です。

  • HDDのXXX.pyファイルにpythonのブログラムを書く(ただテキストファイルに文字を書いただけ)
  • python XXX.py で実行すると、プログラムがメモリに展開される
  • メモリにはアドレスと記憶領域がある。アドレスを指定して、それに紐づいた記憶領域内の値やプログラムを参照する。
  • メモリアドレスを指定して記憶領域の値を読み書きし、CPUが演算処理を行う。

少し難しいように感じる方もいるかもしれませんが、重要なことは、 メモリにはアドレスと記憶領域があり、アドレスを指定して、そのアドレスに格納されているデータを 取り出しているという点です。アドレスを指定する、ここが非常に重要なポイントです。

下記の図はメモリアドレスのイメージになります(完全にイメージなのでアドレスや値は適当です)。

f:id:raspberrypi:20220201153425j:plain
メモリの構造 イメージ

プログラムで操作しているのは、メモリアドレス(記憶領域ではない)

下記にひとつ例を記載します。

    def test1(data_x, func_test2):

        data_x[0] = 10
        # data_xのメモリアドレスからpython言語が配列と識別し、要素0に10を格納する

        func_test2(data_x)
        # func_test2のメモリアドレスからpython言語が関数と識別する
        # data_xのメモリアドレスだけ、func_test2に渡す

    def test2(data_x):
        
        data_x[1] = 20
        # data_xのメモリアドレスからpython言語が配列と識別し、要素1に20を格納する

    x = [1,2,3,4,5] 
    # xに配列を代入
    
    test1(x, test2)
    # test1関数の引数について
    # xは配列データ全てを渡しているのではない。配列の先頭のメモリアドレスだけ渡している。
    # test2は関数のプログラムの全てを渡しているのではない。関数の先頭のメモリアドレスだけ渡している。
    # あまり行わないが関数を引数に渡す時は、関数名のみ書けばよい。

    print(x) # => [10, 20, 3, 4, 5]
    # test1とtest2には、同じメモリアドレスを渡しているので、
    # 同じ配列を操作していることになる。

上記例題のコメントに解説を記載しています。

pythonでは、メモリアドレスから記憶領域のデータを参照するということを自動で行ってくれます。 私たちがpythonのコードで扱っているは、記憶領域の値ではなく、メモリアドレスということを認識してください。 (定数のような変更できないデータの場合は、動作が異なりますが、決まった値が入っているだけなので、 深く考える必要はありません)

そして、データであればデータの先頭アドレス、関数であれば関数の先頭アドレス、 クラスであればクラスの先頭アドレスさえわかれば、あとはpython言語が記憶領域を参照し、 データを適切に識別してくれます。

コード上でコピー(代入)する場合を考えてみてください(関数等の引数に値を渡す場合も同じ)。 データ、関数、クラスそのものをコピーした場合、ものすごい量のデータをコピーすることになりますが、 実際は先頭アドレスだけをコピーしているので、処理はとても軽いのです。

Check!

このアドレスを渡すことを参照渡しと言います。逆に記憶領域のデータを渡すことを値渡しと言います。

C言語では全く逆

少し話は変わりますが、C言語でコピー(代入)をする場合、記憶領域のデータをコピーします。 C言語では、メモリアドレスを扱いたい場合は、自分で記憶領域の データ⇒メモリアドレス の変換しなければなりません。 この操作をポインタと言いますが、メモリ操作は厳密に行わないとすぐにクラッシュします。

C言語とpythonは全く逆のしくみになっています。pythonでは、通常の操作でメモリアドレスを扱うため、 スピードも速く、とてもわかりやすくコードを書くことができます。

ただ、これをプログラマが理解していないと、コピーした別のデータなのか、同じアドレスの同一データなのか? という部分があいまいになり、間違ったコードを書いてしまいます。

重要

  • 変数、関数、クラス等において先頭のアドレスを指定することで、python言語がその変数の値であったり、 関数、クラスを認識し、プログラムを実行してくれる

この感覚はクラスを扱うよう時に、とても重要になりますので、ぜひ覚えておいてください。

今回の解説は以上になります。