Search code examples
pythonlistself-reference

Why in Python a list self-reference doesn't behave the same way when extended or summed?


This is just a theoretical question and doesn't have any use case I believe.

I was playing with lists self reference and I noticed that:

 >>> l = []                                                                                                                                        
 >>> l.append(l)                                                                                                                                   
 >>> l.append(l)                                                                                                                                   
 >>> l                                                                                                                                             
 [[...], [...]]                                                                                                                                     
 >>> l+l                                                                                                                                           
 [[[...], [...]], [[...], [...]], [[...], [...]], [[...], [...]]]   

And ok the output seems fine? Then I tried:

 >>> l = []                                                                                                                                        
 >>> l.append(l)                                                                                                                                   
 >>> l.append(l)                                                                                                                                   
 >>> l                                                                                                                                             
 [[...], [...]]                                                                                                                                    
 >>> l.extend(l)                                                                                                                                   
 >>> l                                                                                                                                             
 [[...], [...], [...], [...]]

I thought l+l and l.extend(l) would behave the same way with the only difference that list+list creates a copy

I then checked references but they are all the same:

 >>> l = [] 
 >>> l.append(l) 
 >>> l.append(l) 
 >>> l 
 [[...], [...]] 
 >>> l+l 
 [[[...], [...]], [[...], [...]], [[...], [...]], [[...], [...]]] 
 >>> e =l+l 
 >>> e[0][0] is e[0][1] 
 True 
 >>> e[0][0] is e[0] 
 True 
 >>> e[0] is e[1] 
 True

TLDR Why

>>> l+l                                                                                                                                           
 [[[...], [...]], [[...], [...]], [[...], [...]], [[...], [...]]]   

But

 >>> l.extend(l)                                                                                                                                   
 >>> l                                                                                                                                             
 [[...], [...], [...], [...]]

Solution

  • The recursive __repr__ for builtin objects checks for the first recursion and prints it.

    In case of .extend() you take the list of 2 lists, and turn them into a list of 4 lists:

                 1
      1.1    1.2    1.3    1.4
    [[...], [...], [...], [...]]
    

    Since each list is itself and prints the same, the recursion ends here.

    In case of the +, the output object is not the same as the other lists:

                                   unique
           1               2               3                4
       1.1    1.2      2.1    2.2      3.1    3.2      4.1    4.2
    [[[...], [...]], [[...], [...]], [[...], [...]], [[...], [...]]]  
    

    You have one outer list of 4, BUT, each sub list contains 2 items. The recursion only starts when you go into depth 2.

    Basically, in the first one 1.1 == 1 but in the second one 1 != unique.