日々の学びと煩悩

idとは一体なんなのか

以前、過去記事でデバッグの見方を記録した際、変数名の取得の方法をメモしていた

wimper-1996.hatenablog.com

肝心の変数名取得のところはここ

get_var_name = [k for k, v in locals().items() if id(v) == id(df_local)]
var_name = get_var_name[0]

df_localは、for文内などのローカルな空間内locals()でのデータフレームの変数名

だが、これを何も見ずにまた書こうとすると間違える。



id(k) == id(df_local)と書いてしまったり、

[k for k, v]ではなく[v for k, v]と書いてしまったり



これの原因は、idをちゃんと理解していないからだな〜と思って調べ出したらなんか深すぎてとまらなかったのでidについてまとめることにした。

(本当は、for文における変数の取り出し方をまとめようと思ったのに....)

idとは

オブジェクトの "識別値" を返します。この値は整数で、このオブジェクトの有効期間中は一意かつ定数であることが保証されています。有効期間が重ならない 2 つのオブジェクトは同じ id() 値を持つかもしれません。 組み込み関数 — Python 3.8.1 ドキュメント

ちょっと調べてみると、こんな記事を見つけた。

qiita.com

pythonにおける演算子isは、idが同一かどうかを指すらしい。

> var1 = [1, 2, 3]
> var2 = [1, 2, 3]
> id(var1) == id(var2)

# 結果
False

これを見た私

「全てのオブジェクトには、識別子が与えらる変数の中身が同じだろうとなかろうと、異なる識別子が与えられるんだ!」

そこで、実験

> var1 = 'hoge'
> var2 = 'hoge'
> id(var1) == id(var2) # 予想:False

# 結果
True




ファ!?




なんでやねん、どゆこと?識別子、一緒じゃん…

色々こんがらがってしまったが、

考えてみると「id」が等しい、すなわちオブジェクトが全く等しいものはそりゃあるような気がする。

私の理解は

イミュータブルなオブジェクトで値が等しいと、idは等しくなる

というもの。

イミュータブルとは、 変更できないオブジェクトのこと。

(イミュータブル) 固定の値を持ったオブジェクトです。イミュータブルなオブジェクトには、数値、文字列、およびタプルなどがあります。これらのオブジェクトは値を変えられません。別の値を記憶させる際には、新たなオブジェクトを作成しなければなりません。 用語集 — Python 3.8.1 ドキュメント

逆にミュータブルとは、変更できるオブジェクトのこと。

例としては、

ミュータブルなオブジェクト

  • list型
  • dict型
  • class 定義文

イミュータブルなオブジェクト

  • str型 文字列
  • int型などの数値
  • タプル

idは、異なるオブジェクトを参照する識別子だから、

hogeというイミュータブル(変更不可能, つまり固有なオブジェクトそのもの)な変数が2つあったら、識別できない

というのが私の理解になっている (間違っていたら指摘お願いします...)。



例えばこれなんかは

> var1 = 'hoge'
> var2 = var1
> id(var1) ==  id(var2)
> id(var2)

# 結果
4550558808
True

これは、var1とvar2が「同じオブジェクト」を「参照」しているためidが等しくなる。

2行目が、var2 = 'hoge'となっても、var1 と var2の参照先は固有のイミュータブルのオブジェクトであるからidが変わらない、ということ。



しかし、リストなどのミュータブルなオブジェクトは、後から要素を書き換えることが可能なため、var1とvar2で初期値が同じ[1, 2, 3] だとしても1つ1つのオブジェクトに最初から異なるidが割り振られる

という理解でいる(これまた間違ってたら指摘お願いします)。



ちなみに

> var2 = str(var2) + 'ee'
> id(var2)

# 結果
4568577224

これは、var2が異なるオブジェクト「hogeee」を参照するようになったため、idが変わったと考えられる

以下の記事が非常に参考になった↓

Python で変数に代入するってなに? | Mastering Python



まぁ、ここまで細かく理解しなくても困ることはあまりないかもしれないが、重要なことは

  • 変数はオブジェクトを「参照するラベル=id」にすぎない
  • idは、基本的に異なる変数に対して異なる値が割り振られる。が、ミュータブルなオブジェクトが全くの同値だった場合、例外的に同じidとなる