Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Types for which "is" keyword may be equivalent to equality operator in Python

For some types in Python, the is operator seems to be equivalent to the == operator. For example:

>>> 1 is 1
True
>>> "a spoon" is "a spoon"
True
>>> (1 == 1) is (2 == 2)
True

However, this is not always the case:

>>> [] == []
True
>>> [] is []
False

This makes sense for mutable types such as lists. However, immutable types such as tuples seem to display the same behavior:

>>> (1, 2) == (1, 2)
True
>>> (1, 2) is (1, 2)
False

This raises several questions:

  1. Is the == / is equivalence related to immutability?
  2. Are the behaviors above specified, or an implementation detail?
  3. Most importantly (and basically), how can I know if an assignment will result in a copy of an object being made, or a reference to it being made?

Update: If assignment is always by reference, why doesn't the following print 2?:

>>> a = 1
>>> b = a
>>> a = 2
>>> b
1

Why isn't this equivalent to the following C snippet:

int a = 1;
int *b = &a;
a = 2;
printf("%d\n", *b);

Apologies for the newbness of this question, but I am a Python novice and feel that it is important to understand this. Is there any reading you would recommend to understand these sort of issues?

like image 348
fmark Avatar asked Dec 02 '22 05:12

fmark


1 Answers

The is operator tests if two objects are physically the same, that means if they have the same address in memory. This can also be tested using the id() function:

>>> a = 1
>>> b = 1
>>> a is b
True
>>> id(a) == id(b)
True

The == operator on the other hand, tests for semantical equality. This can also be overridden by custom classes by implementing the __eq__() function. Semantically, two different lists are equal if their elements are all equal, but physically they will be different objects.

Immutable types like strings and tuples might be pooled by the Python implementation, so that two literal string objects are in fact physically identical. But this does not mean that you can always use is to compare those types, as demonstrated in the following example:

>>> "foobar" is "foobar"   # The interpreter knows that the string literals are
True                       # equal and creates only one shared object.
>>> a = "foobar"
>>> b = "foobar"
>>> a is b        # "foobar" comes from the pool, so it is still the same object.
True
>>> b = "foo"     # Here, we construct another string "foobar" dynamically that is
>>> b += "bar"    # physically not the same as the pooled "foobar".
>>> a == b
True
>>> a is b
False

Assignments in Python always bind the reference to an object to a variable name and never implies a copy.

UPDATE

Analogous to C, think of Python variables always being pointers:

>>> a = 1
>>> b = a
>>> a = 2
>>> b
1

Roughly equivalent to:

const int ONE = 1;
const int TWO = 2;

int *a = &ONE;
int *b = a;  /* b points to 1 */
a = &TWO;    /* a points to 2, b still points to 1 */
like image 195
Ferdinand Beyer Avatar answered Feb 07 '23 16:02

Ferdinand Beyer