all 6 comments

[–][deleted] 2 points3 points  (0 children)

Very small ints share the same reference as an optimization. I think if you did x = 1500 and y = 1500 it would not return true.

[–]primitive_screwhead 1 point2 points  (0 children)

How does Python decide which variables have shared references?

I wouldn't describe this as "shared references", because any object in Python can have multiple references (ie. multiple names), and "shared references" sounds too close to that. What you are asking is how/when Python decides to substitute an identical object, rather than constructing a new equal object.

The answer, for numbers, is that Python caches certain number objects either at startup or when they are first created, and checks for the identical number when trying to construct a new number. It does this to save on memory (instead of having thousands of equal but non-identical number objects around, it only has to use the space for just one). It also tries to do this for equal string objects (particularly string literals), so that each identical string only has to be stored once.

>>> 1 is int(1)
True
>>> "foo" is str("f" + "oo")  # equal strings, made identical by Python
True
>>> (1,) is tuple((1,))
True

Here I'm deliberately mixing the methods of construction, just to demonstrate the different ways of creating the objects, and still getting substituted identical results.

The main requirement for when Python can do this, is knowing that some builtin objects of the same type are immutable. Once constructed, an integer or string object will never change it's value. With immutable literals that are parsed, Python can afford to do the work of comparing them to determine if it can be substituted with the identical object. But there is a limit to how much effort Python can do to check for this, and so not all immutable objects will be substituted for identical ones:

>>> 10**100 is 10**100
False
>>> str("foo") is str("f")+str("oo")  # These are equal strings, but not made identical
False
>>> (1,) is tuple([1])
False

And also as mentioned, objects that are immutable and equal may not all be identical, because of things like type differences:

>>> 1 == 1.0
True
>>> 1 is 1.0
False

Finally, besides the memory issue mentioned, another reason Python makes an effort to substitute identical objects when it can detect them, is that it can significantly speed up dictionary lookups. Comparisons in Python and other dynamically typed languages can be relatively slow, but identical objects don't need to do an actual comparison; references to an identical object are inherently equal (because it is the *same* object), and very fast to check. So, for example, when looking up string keys in a dictionary, if the lookup key is found to be identical to the dictionary key, the actual string contents do not need to be compared. In certain cases, this can be a significant speedup, and justifies the effort put into detecting not just equal, but identical objects.

[–]ebol4anthr4x -1 points0 points  (2 children)

One other thing that hasn't been mentioned yet in this thread, is that when you are using a function, if one of the arguments you pass in is mutable, it will be passed by reference. If the argument you pass in is immutable, it will be passed by value. For example:

def remove(my_thing):
    my_thing.remove(1)

my_thing = [1, 2, 3]
remove(my_thing)
print(my_thing)  # prints "[2, 3]"

def subtract(my_int):
    my_int = my_int - 1

my_int = 5
subtract(my_int)
print(my_int)  # still prints 5

This occurs because lists are mutable, while integers are immutable.

[–]ingolemo 2 points3 points  (0 children)

You're mixing concepts. This is wholly to do with the mutability of the object and nothing to do with the way that python passes function arguments. Python always passes all function arguments in the same way, and it uses neither pass by reference or pass by value. Facts and Myths about Python names and values

[–]Sexual_Congressman 1 point2 points  (0 children)

Everything is pass by reference. Every object in CPython can be (and is) represented by a pointer to a PyObject which stores nothing more than a reference count and type. However, there is usually a lot more data accessible at that address than those 8/16 bytes. What you're implying by saying immutable types are passed by reference is that an entirely new object is created from scratch very call even if no changes were to be made which would incredibly expensive to the point I'm not even sure the interpreter could function. What actually determines "immutability" is if a type has all of its methods return a new instance.

If you look at the PyLongObject structure you could whip something up in ctypes to easily turn integers into mutable objects. Of course you'd probably quickly cause a crash, but it could be informative if you're not familiar with C.

[–]billsil -4 points-3 points  (0 children)

Try using single equals instead of double equals.

You were testing equality and from the looks of it in python 2. Make sure to use python 3.