【参照値の値渡し??】Pythonの変数渡しについての理解 その2

雑学

更新月:2024/12
Pythonの変数渡しについて纏めた記事になります。Pythonの変数渡しについてid関数を使って視覚的に理解を深めてもらう回になります。

Pythonの変数渡しとid()を使った挙動確認

Pythonで関数に変数を渡す際の挙動について、id() 関数を使って実際にどのようにメモリ上でのオブジェクト参照が行われているのかを確認しながら説明します。

id() 関数について

id() 関数は、Pythonでオブジェクトの「識別子」を取得するための組み込み関数です。この関数は、指定したオブジェクトがメモリ上でどの場所に格納されているかを示す一意の整数値を返します。簡単に言えば、オブジェクトのアドレスを確認するために使います。

例えば、同じオブジェクトが複数の変数に参照されている場合、これらの変数は同じ id() を返すことになります。一方で、異なるオブジェクトの場合は、異なる id() が返されます。

値渡しと参照渡しを id() で確認する

Pythonの変数渡しの特徴を、id() を使って具体的に確認してみましょう。ここでは、関数に渡す引数としてミュータブルオブジェクト(リスト)とイミュータブルオブジェクト(整数)を使って説明します。

1. ミュータブルオブジェクト(リスト)の場合

リストなどのミュータブル(変更可能)オブジェクトの場合、関数内で変更を加えると、呼び出し元の変数にも影響が及びます。これを id() を使って確認してみます。

def modify_list(my_list):
    print(f"関数内: my_listのid = {id(my_list)}")  # my_listのidを表示
    my_list.append(4)  # リストに4を追加
    print(f"関数内: my_listのid = {id(my_list)}")  # 変更後のmy_listのidを表示

# 関数を呼び出す前のリスト
original_list = [1, 2, 3]
print(f"関数呼び出し前: original_listのid = {id(original_list)}")

modify_list(original_list)

# 関数を呼び出した後のリスト
print(f"関数呼び出し後: original_listのid = {id(original_list)}")
print(f"最終的なリスト: {original_list}")

このコードを実行すると、次のような出力が得られるはずです。

関数呼び出し前: original_listのid = 140198926058624
関数内: my_listのid = 140198926058624
関数内: my_listのid = 140198926058624
関数呼び出し後: original_listのid = 140198926058624
最終的なリスト: [1, 2, 3, 4]

ポイント:

  • original_listidmy_listid が同じです。これは、関数に渡された引数が元のオブジェクトを参照していることを意味します。
  • リストに新しい要素(4)を追加しても、id は変わりません。これは、リスト自体が変更された(ミュータブルなオブジェクトであるため)だけで、my_listoriginal_list は同じオブジェクトを参照しているからです。

2. イミュータブルオブジェクト(整数)の場合

次に、イミュータブル(変更不可能)オブジェクトの例として整数を使います。整数は一度値が決まると、その内容を変更することはできません。値を変更しようとすると、新しいオブジェクトが作られます。

def modify_integer(num):
    print(f"関数内: numのid = {id(num)}")  # numのidを表示
    num = 10  # 新しい整数を代入
    print(f"関数内: numのid = {id(num)}")  # 変更後のnumのidを表示

# 関数を呼び出す前の整数
original_number = 5
print(f"関数呼び出し前: original_numberのid = {id(original_number)}")

modify_integer(original_number)

# 関数を呼び出した後の整数
print(f"関数呼び出し後: original_numberのid = {id(original_number)}")
print(f"最終的な値: {original_number}")

このコードを実行すると、次のような出力が得られます。

関数呼び出し前: original_numberのid = 140707181216368
関数内: numのid = 140707181216368
関数内: numのid = 140707181216400
関数呼び出し後: original_numberのid = 140707181216368
最終的な値: 5

ポイント:

  • original_numberidnumid が最初は同じです。しかし、num = 10 として新しい整数 10 を代入すると、numid が変わります。これは、整数のようなイミュータブルオブジェクトの場合、新しい値が割り当てられると、新しいオブジェクトが作成されるためです。
  • 結果として、original_numberid は変わらず、関数外での値も変更されていません。

まとめ

Pythonにおける「参照値の値渡し」とは、変数が指し示すオブジェクトの参照が渡されることを意味します。しかし、その参照が「そのまま渡されるわけではなく」、ミュータブルなオブジェクト(例えばリストや辞書)を操作した場合は変更が元のオブジェクトにも反映されます。一方で、イミュータブルなオブジェクト(整数や文字列)を操作しても、元のオブジェクトには影響を与えません。

初心者にとっては、これらの挙動が少し直感的でないかもしれませんが、重要なのはオブジェクトの種類(ミュータブルかイミュータブルか)が変数渡しの結果に大きく影響するということです。これを理解することで、Pythonでの変数の扱いがより明確になるでしょう。

関連記事

外部リンク

生成AIメモ

  • 利用AI:ChatGPT 4o mini、一部利用
  • プロンプト1:id表示を交えての説明もお願いします。まずはhtml形式じゃなくて良いです。
  • プロンプト2:先程の説明もhtml形式(style使わず)で出力させてください
  • プロンプト3:基本的な内容はOKです。コード記述のフォントサイズは一回り小さい形でお願いします。

内容チェック済。