たまに誤解している人がいるので、書いておく。
pythonのオブジェクトにはimmutableという概念がある。これはオブジェクトが変更不可能であるということを示す。intやstr, tupleなどが代表的なimmutableなオブジェクトである。
オブジェクトがimmutableであるかどうかは、オブジェクトがいわゆるシングルトンであるかどうかとはまったく関係ない。
確かに、そんな風に振る舞っている、ように見える状況もある。
>>> a = 1 >>> b = 1 >>> a is b True >>> a = "a" >>> b = "a" >>> a is b True
しかし、tupleで試すと、同様に結果にはならないことがわかる。
>>> a = (1,2,3) >>> b = (1,2,3) >>> a is b False
もう少し、いろいろ見てみる。
>>> all([a is b for a,b in zip(range(100), range(100))]) True >>> all([a is b for a,b in zip(range(1000), range(1000))]) False
不可解だって? まあ、不可解なんだけど、これはpythonの実装の問題である。
pythonは参照カウントGCを持つオブジェクト指向言語である。どんなオブジェクトであろうと生成にはインスタンス生成分のコストがかかるし、参照されなくなったオブジェクトはGCが連れて行く。
それはそれで良いのだが、「小さめの数字」とか「短めの文字列」みたいなしょっちゅう使われるオブジェクトを必要になるたびに生成し、不要になるたびにGCを呼ぶのは無駄である。よって、pythonは内部にキャッシュを持ち、オブジェクトのインスタンスを残しておく。いわゆるインターン*1だと思えば良い。
ここのページでその辺のことには触れられている。
Cool Python Tips: is演算子はimmutable変数に使わないこと
結論を言うと、immutableだからといってシングルトンだと思いこんではいけないし、ましてやis比較などしてはいけない。
*1:python インターンで検索すると就業体験の「インターンシップ」ばっかり出てきて、有益な情報が出てこない・・・