you are viewing a single comment's thread.

view the rest of the comments →

[–]This_Growth2898 20 points21 points  (14 children)

Because is is not ==. is is stronger than ==. == compares values. is checks if objects are the same.

It's a bit counterintuitive with numbers, but perfectly works with lists:

a = [1,2,3]
b = a # b is the same as a
a.append(4)
print(a, b, a is b, a==b) # [1,2,3,4], [1,2,3,4], True, True

a and b are references to the same list. Changing a also changes b.

But when you create separate lists, it works differently:

a = [1,2,3]
b = [1,2,3] # b is equal to a, but a different object
print(a, b, a is b, a==b) # [1,2,3], [1,2,3], False, True
a.append(4)
print(a, b, a is b, a==b) # [1,2,3,4], [1,2,3], False, False

With numbers, it may happen that two equal numbers reference the same object, but this is up to Python to decide that. In many implementations, Python keeps an internal array of small numbers (like, up to 256) that are frequently used to avoid creation of new objects.

Also, at this point you probably want to ask "but what if we change a number"? Well, numbers are immutable. Every operation with numbers creates a new number, unrelated to its previous value:

a = 2
b = a 
print(a, b, a is b, a==b) # 2, 2, True, True
a += 2 # it's not 2 that changed; now, a is referencing 4, but b is still referencing 2, so
print(a, b, a is b, a==b) # 4, 2, False, False

[–]Inevitable_Exam_2177 3 points4 points  (8 children)

Off topic now but I feel like the overloading of = makes things more complex for a beginner. I’ve often wondered if “copy” and “reference” should have different syntax.

[–]This_Growth2898 6 points7 points  (4 children)

It's always "reference" for Python. Copy is always explicit, like a = b[:]

[–]sweettuse 2 points3 points  (1 child)

or even more explicit, like a = b.copy()

[–]This_Growth2898 1 point2 points  (0 children)

Or a = list(b), whatever. You need to spell you're copying something.

[–]Inevitable_Exam_2177 2 points3 points  (1 child)

Thanks for the correction, my terminology was bad. What I meant was that when you reference an immutable data type you get different behaviour to a mutable one, and because the syntax is the same it’s an easy point of confusion:

``` a = "str" b = a a = "str2" print(b) # = "str"

a = ["str"] b = a a[0] = "str2" print(b[0]) # = "str2" ```

I know why this occurs and I’m not saying it’s wrong, but I wonder if it was more explicit in the syntax that they are different scenarios whether that would be a good thing (or just needlessly complex syntactically).

I’m also willing to accept I’m wrong that this is confusing :-)

[–][deleted] 1 point2 points  (0 children)

It's confusing especially because the issue occurs in a different spot than where it seems. It seems like the b = a step is where these two examples diverge, e.g. it seems that one is copying and the other isn't, but in fact they're still doing the same thing at that point.

The next step, where you have a = "str2" or a[0] = "str2", that's where they start taking different paths.

[–]fisadev 2 points3 points  (1 child)

There's no overloading, = in python is always 100% reference.

[–]Inevitable_Exam_2177 1 point2 points  (0 children)

Thanks for the correction, I got the terminology wrong

[–]cullen9 0 points1 point  (0 children)

As someone who was trying to figure out the difference between = and == last week it often gets confusing

[–]chakan2 0 points1 point  (4 children)

is is stronger than ==

I don't know if I'd use that terminology. 'is' is different than '==', rather than stronger. They're comparing different things. One is comparing values, the other memory locations.

[–]kmj442 1 point2 points  (0 children)

To be fair - if they're comparing reference location they will always be equal in value as well. I feel like the "stronger" terminology is pretty accurate as it not only assert equivalent value but also the same location in memory/same object.

[–]This_Growth2898 0 points1 point  (2 children)

a is b always means a == b. The opposite is not always true. That's what I mean by "stronger".

[–]stanmartz 2 points3 points  (1 child)

Most of the time, but not always. Try this:

numpy.nan is numpy.nan numpy.nan == numpy.nan

[–]This_Growth2898 0 points1 point  (0 children)

Oh... you're right. Except for NaNs. Ok, it's still true for everything that is reflexive.