views:

91

answers:

2

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 immutable 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?

+6  A: 

Is the == / is equivalence related to immutability?

No.

See Python ‘==’ vs ‘is’ comparing strings, ‘is’ fails sometimes, why? on why it works on strings, and Python “is” operator behaves unexpectedly with integers on why it works on integers (thus bools for the same reason).

Are the behaviors above specified, or an implementation detail?

Implementation detail.

how can I know if an assignment will result in a copy of an object being made, or a reference to it being made?

Assignment is always by reference. Copying is done only if you explicitly use copy.copy (or something like that).

Edit: By "by reference" I don't mean references in C++. Python's assignment will rebind the variable. It's more like

// int* a, *b;
a = new int(1);
b = a;
a = new int(2);
printf("%d\n", *b);
KennyTM
Updated question in response, please update answer if that's okay.
fmark
@fmark: See update.
KennyTM
Aha, I think I understand better now, thank you. Any reading you can recommend?
fmark
+1 for the links to related questions.
Ferdinand Beyer
+7  A: 

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 */
Ferdinand Beyer
oversimplified: there are no variables in python, only names
hop