Search code examples
pythonpython-3.xlistassignment-operator

What is happening when I assign a list with self references to a list copy with the slice syntax `mylist[:] = [mylist, mylist, ...]`?


I was just looking at the implementation of functools.lru_cache, when I stumbled across this snippet:

root = []  # root of the circular doubly linked list
root[:] = [root, root, None, None]  # initialize by pointing to self

I am familiar with circular and doubly linked lists. I am also aware that new_list = my_list[:] creates a copy of my_list. When looking for slice assignments or other implementations of circular doubly linked lists, I could not find any further information on this specific syntax.

Questions:

  1. What is going on in this situation.
  2. Is there a different syntax to achieve the same result?
  3. Is there a different common use case for some_list[:] = some_iterable (without the self reference)?

Solution

  • in

    root[:] = [root, root, None, None]
    

    left hand slice assignment just says that the reference of root is reused to hold the contents of the right part.

    So root reference never changes, and yes, in a list you can reference yourself (but don't try recursive flattening on those :). The representation displays a "recursion on list" in that case.

    >>> root
    [<Recursion on list with id=48987464>,
     <Recursion on list with id=48987464>,
     None,
     None]
    

    and printing it shows ellipsis:

    >>> print(root)
    [[...], [...], None, None]
    

    note that you don't need slice assignment for this. There are simple ways to trigger a recursion:

    >>> root = []
    >>> root.append(root)
    >>> root
    [<Recursion on list with id=51459656>]
    >>> 
    

    using append doesn't change reference as we all know, it just mutates the list, adding a reference to itself. Maybe easier to comprehend.