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:

  • for integers, answer digs in source can found here.
  • for strings, handful of answers can found here, here , here.

Comments

Popular posts from this blog

Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12:test (default-test) on project.Error occurred in starting fork -

windows - Debug iNetMgr.exe unhandle exception System.Management.Automation.CmdletInvocationException -

configurationsection - activeMq-5.13.3 setup configurations for wildfly 10.0.0 -