3

I have two list.

list1=["divyansh","jain","python"]
list2=["divyansh","jain","python"]

Both list have exactly the same data.

But when we apply the is identity operator it gives us false and also the memory address is different.

I know that in python everything is an object. If I declare another variable with same data value, both the variable points to the same object. Then why does this does not work in the case of list data type.

I know that python allocates default object at runtime for int values in range 0 to 255, boolean values & empty string.

Why is list2 pointing to some different memory address when list1 was created in first place with exact same values?

Code :

x=300
y=300
print("Memory Address of variable x is : ",id(x))
print("Memory Address of variable y is : ",id(y))
print(x is y)
print(x is not y)
list1=["divyansh","jain","python"]
list2=["divyansh","jain","python"]
print("Memory Address of variable list1 is : ",id(list1))
print("Memory Address of variable list2 is : ",id(list2))
print(list1 is list2)
print(list1 is not list2)

Output : 
Memory Address of variable x is :  140185049313168
Memory Address of variable y is :  140185049313168
True
False
Memory Address of variable list1 is :  140185048064584
Memory Address of variable list2 is :  140185048053000
False
True

Creation of object is more time consuming and an expensive operation rather than searching for it and assigning the same memory address to it. I get it that for mutable objects its not possible , in future if we change list2 the list1 data will be effected and for this reason it created diff object. But for fundamental immutable data types like int,float,str its allocating same memory but in case of immutable data types like bytes,tuple,frozenset,complex,range it is not allocating the same memory although it has the same data value.

Other Data types example :

tuple1=("divyansh","jain","python")
tuple2=("divyansh","jain","python")
print("Memory Address of variable tuple1 is : ",id(tuple1))
print("Memory Address of variable tuple2 is : ",id(tuple2))
print(tuple1 is tuple2)
print(tuple1 is not tuple2)

bytes1=[1,2,3]
bytes2=[1,2,3]
b1=bytes(bytes1)
b2=bytes(bytes2)
print(type(b1),type(b2))
print(id(b1))
print(id(b2))
print(bytes1 is bytes2)

a=10.5
b=10.5
print(type(a),type(b))
print(id(a))
print(id(b))
print(a is b)

c1=10+20j
c2=10+20j
print(type(c1),type(c2))
print(id(c1))
print(id(c2))
print(c1 is c2)

s1="Dj"
s2="Dj"
print(type(s1),type(s2))
print(id(s1))
print(id(s2))
print(s1 is s2)


f1=frozenset({"Dj"})
f2=frozenset({"Dj"})
print(type(f1),type(f2))
print(id(f1))
print(id(f2))
print(f1 is f2)

r1=range(10)
r2=range(10)
print(type(r1),type(r2))
print(id(r1))
print(id(r2))
print(r1 is r2)

Memory Address of variable tuple1 is : 140088826761792
Memory Address of variable tuple2 is : 140088826762008
False
True
<class 'bytes'> <class 'bytes'>
140088827913280
140088827388192
False
<class 'float'> <class 'float'>
140088827982304
140088827982304
True
<class 'complex'> <class 'complex'>
140088827402864
140088827402896
False
<class 'str'> <class 'str'>
140088826759184
140088826759184
True
<class 'frozenset'> <class 'frozenset'>
140088827366088
140088827365640
False
<class 'range'> <class 'range'>
140088846540448
140088827189840
False
  • Python caches small integers, but not small lists. That's all. – timgeb May 23 '21 at 09:18
  • To answer your question, **because they are two different list objects**. Why *would you expect them to have the same ID?* – juanpa.arrivillaga May 23 '21 at 09:42
  • " If I declare another variable with same data value, both the variable points to the same object." No, that isn't true at all. As this simple example proves. – juanpa.arrivillaga May 23 '21 at 09:43
  • 2
    Fundamentally, your assumption that immutable objects with the same value always have the same identity is **simply incorrect**. – juanpa.arrivillaga May 23 '21 at 09:47
  • 1
    What you are looking at are optimization techniques for dealing with primitive data types. List, tuple, dict, set, etc. are compound data types, and it just does not worth it: you have to create the complete in-memory form of them first, and then you could check if you have it somewhere else already. – tevemadar May 23 '21 at 10:03

1 Answers1

3

In the standard case of object programming: when you create a new object, the language/computer will reserve a new memory space and adress for it.

In Python when you create objects like list/containers, which are mutable objects, each one has its own memory address. So you can work with them and modify one without modifying the second one. This is necessary, if the adress was the same, it would be one same object, with two names/pointers.

This is neccessary to handle changes of the list1 and list2 without modifying the other. As lists are mutabe objects.

To check for content identity you have to check each item inside the lists. In Python use of '==' operator works for content comparison with, numbers, lists, tuples, ...

It is different than with numbers which are immutables objects in Python. As they are immutable and will never change, Python optimizes this by pointing to the same memory address when the same number is reused. (it is a kind of Singleton pattern)

This optimization choice was made because creating a new number object each time would have been to much time and memory consuming. And also the number of memory allocation/deallocation would have been too much also.

Malo
  • 1,233
  • 1
  • 8
  • 25
  • But then why is it not in the case of tuple ? Tuple are immutable. tuple1=("divyansh","jain","python") tuple2=("divyansh","jain","python") print("Memory Address of variable tuple1 is : ",id(tuple1)) print("Memory Address of variable tuple2 is : ",id(tuple2)) print(tuple1 is tuple2) print(tuple1 is not tuple2) Memory Address of variable tuple1 is : 140228882485824 Memory Address of variable tuple2 is : 140228882486040 False True – Divyansh Jain May 23 '21 at 08:39
  • Numbers are a special case. I cannot say the exact explanation for tuples. But you have to know you should use == whenever possible to check for equality test between two objects content, it works for numbers, lists, and tuples. Checking for memory adress equality does not seems to be a good paractice in a standard case. – Malo May 23 '21 at 08:43
  • I am not concerned about the equality of the variable. My concern is regarding memory allocation of the object. For this reason i was using identity operator is just to check what happens when i create an immutable or mutable objects with same value. Does it create a second object or it searches for the first object having the same valuse and point the second variable to that object. – Divyansh Jain May 23 '21 at 08:45
  • Ok so except for numbers, when you use a new object, it will have a new memory adress. Different objects have different memory adresses. Or do you have a more specific case or question to make it clear for me? – Malo May 23 '21 at 08:46
  • we already know that in python at runtime only PVM will initialize default objects for int values in range 0-255, boolean values and empty string. So now when i use to assign 300 which is out of range to two different variable. Both of them are pointing to same memory address. Int is immutable and so it tuple then why does not the concept holds good in case of tuple or list when they have exactly same value. Why does different objects are getting created at memory level (in case of tuple also which is immutable) although it have same data. – Divyansh Jain May 23 '21 at 08:59
  • 3
    This is not a concept but an arbitrary implementation and optimization choice of the language programmers, and you may not rely on it. As lists are mutable, it is mandatory to have a different object in memory and so a different address, no choice here. Maybee you can find an exaplanation/text in the PEPs of Python here: https://www.python.org/dev/peps/#introduction – Malo May 23 '21 at 09:01
  • Ok will look for the implementation. Why does this implemention is not generic and why does it differs. Thanks @Malo for your time. :) – Divyansh Jain May 23 '21 at 09:07
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/232759/discussion-between-divyansh-jain-and-malo). – Divyansh Jain May 23 '21 at 09:07
  • Exactly , That's my doubt . Creation of object is more time consuming and an expensive operation rather than searching for it and assigning the same memory address to it. I get it that for mutable objects its not possible , in future if we change list2 the list1 data will be effected and for this reason it created diff object. But for fundamental immutable data types like int,float,str its allocating same memory but in case of immutable data types like bytes,tuple,frozenset,complex,range it is not allocating the same memory although it has the same data value. – Divyansh Jain May 23 '21 at 09:35
  • 2
    @DivyanshJain *you should always assume a new object is created*. For *immutable objects*, the Python runtime reserves the right to optimize this. That is **an implementation detail**. This isn't a feature of the language, part of the standerd. Actually, for the cases of `None`, `True`, and `False` they are langauge guaranteed singletons, but that is not the case for all immutable objects at all. The premise that "if an object is immutable, and it has the same value, then it must be the same object" is **simply a false premise** – juanpa.arrivillaga May 23 '21 at 09:44
  • 1
    @DivyanshJain also note, sometimes, `tuple` objects *are cached* by the peephole optimizer. But again, you should not ever rely on this. – juanpa.arrivillaga May 23 '21 at 09:46
  • 1
    "Exactly , That's my doubt . Creation of object is more time consuming and an expensive operation rather than searching for it and assigning the same memory address to it." That is absolutely not true in general at all. – juanpa.arrivillaga May 23 '21 at 09:49
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/232765/discussion-between-divyansh-jain-and-juanpa-arrivillaga). – Divyansh Jain May 23 '21 at 10:34