言語仕様に関しては、準拠するPythonコンパイラとランタイムは、不変型のインスタンスに対して、新しいインスタンスを作成するか、必要な値に等しい同じ型の既存のインスタンスを見つけて、新しい参照を使用することが完全に許可されています。その同じインスタンス。これはis
、不変要素間の使用またはIDによる比較が常に正しくないことを意味し、マイナーリリースは、最適化を強化するためにこの問題の戦略を微調整または変更する可能性があります。
実装に関しては、トレードオフは非常に明確です。既存のインスタンスを再利用しようとすると、そのようなインスタンスを見つけるのに費やした時間(おそらく無駄になる)が発生する可能性がありますが、試行が成功すると、メモリ(および割り当て時間)がいくらか節約されます。その後、新しいインスタンスを保持するために必要なメモリビットを解放します)。
これらの実装のトレードオフを解決する方法は完全には明らかではありません。適切な既存のインスタンスが見つかる可能性が高く、検索が(失敗した場合でも)高速であることを示すヒューリスティックを特定できる場合は、検索を試行することをお勧めします。 -ヒューリスティックが示唆する場合は再利用しますが、それ以外の場合はスキップします。
あなたの観察では、それが完全に安全で、速く、そして単純であるときに、わずかなのぞき穴最適化を実行する特定のドットリリース実装を見つけたようです。したがって、割り当てAからDはすべてAとまったく同じになります(ただし、EからFは、オプティマイザーの作成者がセマンティクスを想定するのに100%安全ではないと合理的に考えている可能性がある名前付きの関数またはメソッドを含むため、そうしないでください。
したがって、同じインスタンスを再利用するAからDは、AとBに要約されます(CとDは、まったく同じ構成にのぞき穴最適化されるため)。
その再利用は、コンパイラの戦術/オプティマイザのヒューリスティックを明確に示唆しており、同じ関数のローカル名前空間内の不変型の同一のリテラル定数が、関数内の1つのインスタンスのみへの参照に折りたたまれます.func_code.co_consts
(関数とコードの属性に現在のCPythonの用語を使用するため)オブジェクト)-1つの関数内で同じ不変定数リテラルを再利用することがいくらか頻繁であり、利点が何度も発生する間(関数が実行されるたびに)、価格は1回だけ(コンパイル時に)支払われるため、合理的な戦術とヒューリスティック多分ループ内など)。
(これらの特定の戦術とヒューリスティックは、明らかに前向きなトレードオフを考えると、最近のすべてのバージョンのCPythonに浸透しており、IronPython、Jython、およびPyPyにも浸透していると思います;-)。
Python自体または同様の言語用のコンパイラ、ランタイム環境、のぞき穴オプティマイザなどを作成することを計画している場合、これはやや価値があり興味深い研究です。内部の深い研究(もちろん、特定のものの癖に固執しないように、多くの異なる正しい実装の理想的です-Pythonは現在、言うまでもなく、少なくとも4つの別々の生産に値する実装を楽しんでいますそれぞれのいくつかのバージョン!)は、間接的に、1つをより優れたPythonプログラマーにするのにも役立ちます-しかし、言語自体によって保証されているものに焦点を当てることは特に重要です。 「ちょうど起こる」部分のため言語仕様によってそうなること)は、いずれかの実装の次のポイントリリースで完全に変更される可能性があり、プロダクションコードが誤ってそのような詳細に依存している場合は、厄介な驚きを引き起こす可能性があります;-)。さらに、言語で義務付けられた動作ではなく、このような変数の実装の詳細に依存する必要はほとんどありません。もちろん、オプティマイザー、デバッガー、プロファイラーなどをコーディングしている場合を除きます。 )。