5

I am not able to figure out what is happening here. Appending reference to range function is kind of creating a recursive list at index 3.

>>> x = range(3)
[0, 1, 2]
>>> x.append(x)
[0, 1, 2, [...]]
>>> x[3][3][3][3][0] = 5
[5, 1, 2, [...]]

Whereas, when I try this:

 >>> x = range(3)
 [0, 1, 2]
 >>> x.append(range(3))
 [0, 1, 2, [0, 1, 2]]

I can easily deduce the reason for the second case but not able to understand what appending reference to range function is doing to the list appended.

4
  • 3
    Why is this tagged both Python 2 and 3? range behaves differently in 2 and 3. Commented Apr 3, 2016 at 14:20
  • 2
    Lists are passed by reference in python. This means that in the first scenario, you are appending the pointer to x, not the value of x. Because x now contains a pointer to x, it calls itself recursively at that point. Commented Apr 3, 2016 at 14:21
  • @JacobH: saying "lists are passed by reference" makes it seem like lists might behave differently from other objects. All objects are passed the same way (although people argue about what the right phrase to describe that is.) Commented Apr 3, 2016 at 14:36
  • @interjay I mistakenly did that :( Commented Apr 3, 2016 at 14:57

2 Answers 2

9

In python2, ranges are lists.

lists, and most of the things in python are objects with identities.

li = [0,1]
li[1] = li    # [0, [...]]
              # ^----v
id(li)        # 2146307756
id(li[1])     # 2146307756

Since you're putting the list inside itself, you're creating a recursive data structure.

Sign up to request clarification or add additional context in comments.

3 Comments

Please note that this is Python 2-specific. Ranges are entirely different in Python 3, returning a lazily-evaluated range object, not a list at all.
@Karoly thanks for the answer but I am not able to understand why value assignment of 5 is working. Whatever I have learnt is that if I use a[1][0] = 5, then it means assign 5 to 0 index at list of list at index 1.
if you meant my example: li[1] is li, so it's simply li[0]=5.
0

First this is strange, and you probably should not use this in practice. The issue is not specific to range function and has to do with references. When you call x.append(x), you essentially say that x[-1] is x. So when you modify x[0], you also modify x[-1][0], x[-1][-1][0] etc.

To see that this is not range specific, you could use copy.copy:

from copy import copy

x = range(1)
x.append(x)  # here x[1] is reference to x itself (same object)
print(x[0], x[1][0], x[1][1][0])
x[0] = 1
print(x[0], x[1][0], x[1][1][0])  # all values change

# 

x = range(1)
x.append(copy(x))  # x[1] is a copy of x at previous state (new object)
print(x[0], x[1][0])  # cannot call x[1][1][0] -> x[1][1] is an int
x[0] = 1
print(x[0], x[1][0])  # only the first value changes

Output:

(0, 0, 0)
(1, 1, 1)
(0, 0)
(1, 0)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.