はじめに
Pythonでは、プログラム実行時、生成されたデータにオブジェクトIDという識別子が割り振られます。
オブジェクトIDは、各オブジェクトを区別できるように一意な数値によって表現されます。
本記事では、Pythonで使用されるオブジェクトの中でも、リスト型オブジェクトに焦点を当てて、オブジェクト参照の動作を確認します。
※本記事の最後に疑問も記載しているのでぜひご覧ください。
確認
検証1
まず、リスト型変数を作成し、オブジェクトIDを確認します。
lst1 = [1,2,3]
lst2 = [1,2,3]
# 出力
print(id(lst1))
print(id(lst2))
- 結果
4562150912 # lst1のオブジェクトID
4562745728 # lst2のオブジェクトID
変数lst1と変数lst2は、同じ値こそ格納されているものの、オブジェクトとしては別ものであるため異なるIDが割り振られています。
検証2
それでは、リストそのものと、そのリストを格納した変数ではどうでしょうか?
lst1 = [1,2,3]
# 出力
print(id([1,2,3]))
print(id(lst1))
- 結果
4376885184 # [1,2,3]のオブジェクトID
4376307136 # lst1のオブジェクトID
こちらも、[1,2,3]と変数lst1は別オブジェクトとして扱われています。
検証3
次は、リスト型の変数を別の変数に格納した場合はどうでしょうか?
lst1 = [1,2,3]
lst2 = lst1
# 出力
print(id(lst1))
print(id(lst2))
- 結果
4440778240 # lst1のオブジェクトID
4440778240 # lst2のオブジェクトID
変数lst1と変数lst2のオブジェクトIDが等しくなりました。
検証4
では、同じオブジェクトIDを参照している変数の値を変更した場合はどのような処理になるでしょうか?
#検証3の続き
lst1.append(4)
# 出力
print(id(lst1))
print(id(lst2))
- 結果
4368066048 # lst1のオブジェクトID
4368066048 # lst2のオブジェクトID
両変数とも同じオブジェクトIDになりました。
即ち、値の出力も等しくなります。
# 出力
print(lst1)
print(lst2)
# 結果
[1, 2, 3, 4] # lst1の値
[1, 2, 3, 4] # lst2の値
まとめ
リスト型の変数は、リストそのものを代入した場合、新規のオブジェクトが生成されたものとして処理されます。
対して、リスト型変数を代入した場合、代入したリスト型変数を参照することになります。
結果、両変数ともに同じオブジェクトとして扱われ、出力した際の値も等しくなります。
ちなみに、リスト型変数をコピーして異なるオブジェクトを生成したい場合、copy()メソッドを使用します。
lst1 = [1,2,3]
lst2 = lst1.copy()
# 出力
print(id(lst1))
print(id(lst2))
# 結果
4567344576 # lst1のオブジェクトID
4567922624 # lst2のオブジェクトID
疑問
検証の総括として、各検証の内容をまとめて実行してみたところ、
lst1 = [1,2,3]
lst2 = lst1
# 出力
print(id([1,2,3]))
print(id(lst1))
print(id(lst2))
# 結果
4546345344 # [1,2,3]のオブジェクトID
4545750528 # lst1のオブジェクトID
4545750528 # lst2のオブジェクトID
と想定通りの値になりました。
しかし、続けて以下を実行したところ、
lst2 = [1,2,3]
# 出力
print(id(lst2))
# 結果
4546345344 # lst2のオブジェクトID
というように、[1,2,3]のオブジェクトIDと変数lst2のオブジェクトIDが等しくなりました。
これは、何回同じ処理を実行しても両オブジェクトIDが等しくなるという結果でした。
ためしに、つづけて以下を実行したところ、
lst3 = [1,2,3]
# 出力
print(id(lst3))
# 結果
4546601280 # lst3のオブジェクトID
といったように、続けて生成した変数lst3では異なるオブジェクトIDが割り振られていました。
何らかの法則があるのでしょうか。。。