Adding to a list itself. What happens?

Asked

Viewed 79 times

3

l1 = [1, 2, 3]
l2 = l1
l1.append(l2)
print(l1)

Why does this algorithm return a three-point list? What does this new list mean?

  • this is the site of the OS in Portuguese, translate your question

  • As you are creating a reference of L1 in L2, L2 represents L1. When you made the append, you created a "pointer" of L1 within L1. That is, the fourth position of L1 will point to L1. It’s as if the fourth position is the list itself inside it.

  • Why the rudeness and sarcasm, @Ricardo Pontual ? This is SO, not Facebook. developeer4rt5-9, elaborate your question better, so we can understand your doubt.

  • 2

    @Thiagopetherson There was no rudeness/sarcasm. The question was in English in [pt.so], the orientation to translate the question whether it was necessary.

  • I got it, I’m on my cell phone, I didn’t pay attention. Disregard my comment, I apologize.

1 answer

2

Since you are adding the list to it, it will create a recursion. The ellipsis are displayed precisely so that the display is possible, otherwise it would be impossible to define what the output would be.

Consider the list you built after adding it to yourself:

l1 = [1, 2, 3, l1]

If you did print(l1) the output would be, in theory, [1, 2, 3, l1], but the value of l1 within the list would also be evaluated and therefore the output would be:

[1, 2, 3, [1, 2, 3, l1]]

Gosh, but the l1 appeared again and would also be evaluated to generate output, producing:

[1, 2, 3, [1, 2, 3, [1, 2, 3, l1]]]

And again...

[1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, l1]]]]

And again...

[1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, l1]]]]]

This would have no end, so the Python developers chose to display only an reticence.

[1, 2, 3, [...]]

And a list that has itself is a cyclical list. It seems to make little sense, but it is possible to do this because internally (there in C) the Python list is implemented in a pointer structure for the type PyObject, which is the type that encompasses all objects in Python.

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size
     *     ob_item == NULL implies ob_size == allocated == 0
     * list.sort() temporarily sets allocated to -1 to detect mutations.
     *
     * Items must normally not be NULL, except during construction when
     * the list is not yet visible outside the function that builds it.
     */
    Py_ssize_t allocated;
} PyListObject;

So when you add the list to it, you’re internally just adding a pointer to C, which references the list itself, into the list. When you access the value in l1[3] (in this example) basically you will be accessing the value represented by this pointer that points to the list itself, returning a list of 3 numbers and a pointer (which will also point to itself (recursive)).

The fact that it is a pointer allows you to do this since its value does not need to be evaluated whenever you need the list value.

You can confirm that they are the same objects through the identity operator is.

assert l1 is l1[3]
assert l1 is l1[3][3]
assert l1 is l1[3][3][3]
assert l1 is l1[3][3][3][3]
assert l1 is l1[3][3][3][3][3][3][3][3][3][3][3][3][3][3][3][3]

All checks return to True.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.