python - Why does '() is ()' return True when '[] is []' and '{} is {}' return False? -
from i've been aware of, using [], {}
or ()
instantiate objects returns new instance of list, dict
or tuple
respectively; new instance object a new identity.
this pretty clear me until tested , noticed () ()
returns true
instead of expected false
:
>>> () (), [] [], {} {} (true, false, false)
as expected, behavior manifested when creating objects list()
, dict()
, tuple()
respectively:
>>> tuple() tuple(), list() list(), dict() dict() (true, false, false)
the relevant piece of information find in the docs tuple()
states:
[...] example,
tuple('abc')
returns('a', 'b', 'c')
,tuple([1, 2, 3])
returns(1, 2, 3)
. if no argument given, constructor creates new empty tuple,()
.
suffice say, isn't sufficient answering question.
so, why empty tuples have same identity whilst others lists or dictionaries not?
in short:
python internally creates c
list of tuple objects first element contains empty tuple. every time tuple()
or ()
used, python return existing object contained in aforementioned c
list , not create new one.
such mechanism not exist dict
or list
objects are, on contrary, recreated scratch every time.
this related fact immutable objects (like tuples) cannot altered and, such, guaranteed not change during execution. further solidified when considering frozenset() frozenset()
returns true
; ()
empty frozenset
is considered singleton in implementation of cpython
. mutable objects, such guarantees not in place and, such, there's no incentive cache 0 element instances (i.e contents change identity remaining same).
take note: this isn't 1 should depend on, i.e 1 shouldn't consider empty tuples singletons. no such guarantees explicitly made in documentation 1 should assume implementation dependent.
how done:
in common case, implementation of cpython
compiled 2 macros pytuple_maxfreelist
, pytuple_maxsavesize
set positive integers. positive value these macros results in creation of array of tuple
objects size pytuple_maxsavesize
.
when pytuple_new
called parameter size == 0
makes sure add new empty tuple list if doesn't exist:
if (size == 0) { free_list[0] = op; ++numfree[0]; py_incref(op); /* incref never freed */ }
then, if new empty tuple requested, 1 located in first position of list going returned instead of new instance:
if (size == 0 && free_list[0]) { op = free_list[0]; py_incref(op); /* rest snipped brevity.. */
one additional reason causing incentive fact function calls construct tuple hold positional arguments going used. can seen in load_args
function in ceval.c
:
static pyobject * load_args(pyobject ***pp_stack, int na) { pyobject *args = pytuple_new(na); /* rest snipped brevity.. */
which called via do_call
in same file. if number of arguments na
zero, empty tuple going returned.
in essence, might operation that's performed makes sense not reconstruct empty tuple every single time.
further reading:
a couple more answers shed light on cpython
's caching behaviour immutables:
Comments
Post a Comment