私が知っていることから、_[], {}
_または_()
_を使用してオブジェクトをインスタンス化すると、それぞれ_list, dict
_またはTuple
の新しいインスタンスが返されます。 新しいアイデンティティを持つ新しいインスタンスオブジェクト。
実際にテストしてみると、これは私にはかなりはっきりしていて、_() is ()
_が実際にTrue
の代わりにFalse
を返すことがわかりました。
_>>> () is (), [] is [], {} is {}
(True, False, False)
_
予想どおり、この動作は list()
、 dict()
および Tuple()
それぞれ:
_>>> Tuple() is Tuple(), list() is list(), dict() is dict()
(True, False, False)
_
Tuple()
=のドキュメントで見つけることができる唯一の関連情報:
[...]たとえば、
Tuple('abc')
は_('a', 'b', 'c')
_を返し、Tuple([1, 2, 3])
は_(1, 2, 3)
_を返します。 引数が指定されていない場合、コンストラクターは新しい空のタプル_()
_。を作成します
これは私の質問に答えるには十分ではありません。
では、なぜ空のタプルは同じアイデンティティを持っているのに、リストや辞書のような他のタプルはそうでないのですか?
Pythonは、最初の要素に空のタプルを含むタプルオブジェクトのC
リストを内部的に作成します。 Tuple()
または_()
_を使用するたびに、Pythonは前述のC
リストに含まれている既存のオブジェクトを返し、新しいオブジェクトを作成しません。
そのようなメカニズムは、逆に、毎回最初から再作成されるdict
またはlist
オブジェクトには存在しません。
これは、(タプルなどの)不変オブジェクトが変更できないため、実行中に変更されないことが保証されているという事実に関連している可能性が高いです。 frozenset() is frozenset()
がTrue
を返すことを考慮すると、これはさらに固まります。 _()
_のように空のfrozenset
CPython
の実装ではシングルトンと見なされます 。変更可能なオブジェクトでは、そのような保証は適切ではありません。したがって、ゼロ要素インスタンスをキャッシュするインセンティブはありません(つまり、IDが同じでコンテンツが変更される可能性があります)。
注意してください:これは依存すべきものではありません。つまり、空のタプルをシングルトンと見なすべきではありません。ドキュメントではそのような保証は明示的に行われていないため、実装に依存していると想定する必要があります。
最も一般的なケースでは、CPython
の実装は、2つのマクロ _PyTuple_MAXFREELIST
_ および _PyTuple_MAXSAVESIZE
_ を正の整数に設定してコンパイルされます。これらのマクロの正の値により、サイズ_PyTuple_MAXSAVESIZE
_の Tuple
オブジェクトの配列 が作成されます。
_PyTuple_New
_がパラメーター_size == 0
_で呼び出されると、リストにまだ存在しない場合は、必ずリストに 新しい空のタプルを追加 します。
_if (size == 0) {
free_list[0] = op;
++numfree[0];
Py_INCREF(op); /* extra INCREF so that this is never freed */
}
_
次に、新しい空のタプルが要求された場合、 このリストの最初の位置 にあるタプルが、新しいインスタンスの代わりに返されます。
_if (size == 0 && free_list[0]) {
op = free_list[0];
Py_INCREF(op);
/* rest snipped for brevity.. */
_
これをインセンティブにするもう1つの理由は、関数呼び出しが、使用される位置引数を保持するためのタプルを構成するという事実です。これは、_load_args
_の _ceval.c
_ 関数で確認できます。
_static PyObject *
load_args(PyObject ***pp_stack, int na)
{
PyObject *args = PyTuple_New(na);
/* rest snipped for brevity.. */
_
同じファイルで _do_call
_ によって呼び出されます。引数の数na
がゼロの場合、空のタプルが返されます。
本質的に、これは頻繁に実行される操作である可能性があるため、空のタプルを毎回再構築しないことが理にかなっています。
さらにいくつかの回答が、CPython
のイミュータブルを使用したキャッシング動作を明らかにします。