Search code examples
pythonpython-3.xlistaliasobject-reference

Two names points to the same object in python


Consider the following example:

class Test:
    def __init__(self, lis: list):
        self.list = lis


lis = [1, 2, 3]
obj1 = Test(lis)
obj2 = Test(lis)

print(obj1 is obj2)
print(obj1.list is obj2.list)

obj1.list.reverse()
print(obj2.list)

Output :

False
True
[3, 2, 1]

Explanation:

I create 2 objects of the same class,and the "list" of each object is [1, 2, 3]. Testing if the names obj1,obj2 are referencing the same object the answer is negative (False). But when I test if obj1.list is obj2.list, we get 'True' as an answer.Thus when I reverse the list of the name obj1,the list is also reversed of the name obj2, because it is the same list for both names.

What I need is a way to reverse the list for obj1, but not for obj2. So I need to create a new list.

In the end,this will be the result:

obj1.list.reverse()
print(obj2.list)

Expected output:

[1, 2, 3]

Solution

  • The copy method in Python returns a shallow copy of a list. Shallow copy means that: any modification made in the new list won’t affect the original list.

    For example:

    lis1=['a','b','c']
    print(lis1)
    lis2=lis1
    print(lis2)
    lis1.pop()
    print(lis1, lis2)
    

    The output is:

    ['a', 'b', 'c']
    ['a', 'b', 'c']
    ['a', 'b'] ['a', 'b']
    

    In this example, the lis1 and lis2 refer to the same address. Thus any changes in either of them will result in changes in the other as well.

    We can solve this problem by using the copy method of list or by using the copy module.

    For example:

    lis1=['a','b','c']
    print(lis1)
    lis2=lis1.copy()
    print(lis2)
    lis1.pop()
    print(lis1, lis2)
    

    Output:

    ['a', 'b', 'c']
    ['a', 'b', 'c']
    ['a', 'b'] ['a', 'b', 'c']
    

    In this example, the lis2 is a copy of the lis1 stored at a different address hence when we change lis1 no change is seen in lis2.

    Similarly copy module can be used too. For example:

    import copy
    
    lis1=['a','b','c']
    print(lis1)
    lis2=copy.copy(lis1)
    print(lis2)
    lis1.pop()
    print("list1=",lis1,"list2=", lis2)
    

    Output:

    ['a', 'b', 'c']
    ['a', 'b', 'c']
    list1= ['a', 'b'] list2= ['a', 'b', 'c']
    

    Similarly your problem can be solved using copy method.

    class Test:
        def __init__(self, lis: list):
            self.list = lis
    
    lis = [1, 2, 3]
    obj1 = Test(lis)
    obj2 = Test(lis)
    obj2new=obj2.list.copy()
    
    print(obj1 is obj2)
    print(obj1.list is obj2.list)
    
    obj1.list.reverse()
    print(obj2new)
    

    Now, the desired output is returned:

    False
    True
    [1, 2, 3]
    

    Hope this was helpful!