6

When I define a list in a "generic" way:

>>>a=[[]]*3
>>>a
[[],[],[]]

and then try to append only to the second element of the outer list:

>>>a[1].append([0,1])
>>>a
[[[0,1]], [[0,1]], [[0,1]]]

it appends to all elements of the outer list as can be seen above, probably due to the fact that the elements are references to the same list and not different lists (why does it work that way?). How can I actually create a list in the same "generic" way, such that the inner lists would be different lists and not just references. Thanks.

1 Answer 1

10

You are correct, they are all references to one list.

[[] for _ in range(3)]

is a common way to create a list of independent empty lists. You can use xrange on Python 2.x, but it won't make a difference if the length is actually as small as in your example.

Not sure how to explain the reason for this (the reason is that it's implemented this way), but you can see that this behavior is documented (at least in passing) here:

Operation       Result                              Notes
s * n, n * s    n shallow copies of s concatenated  (2)

The word "shallow" here means exactly that: the elements are copied by reference. "Note 2" at the linked page also answers your question.

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

5 Comments

Performing a shallow copy is a good design choice. Doing a deep copy would be much more complicated and expensive. Also it would be an easy way to break singletons: [True] * n and suddenly there are n different instances of True(or whatever user-defined singleton), which you obviously don't want.
Thanks. You have mentioned I can use "range" if the length is small? In my real project the length can be as big as 10000. Can I still use "range"? I think it would still work for than number, wouldn't it?
@Gregory it sure would, but a list of 10000 numbers would be created and immediately deleted in the process. That probably won't eat much memory, but is likely to be a bit slower than xrange. You can time both and see.
@Gregory R - the difference is trivial for 10000 objects. You can experiment with it yourself with timeit. Bring up the python interpreter and then paste from timeit import timeit;timeit("[i for i in range(10000)]", number=10000)/10000. Then try again with xrange. It was about 100 microseconds on my machine.
@tdelaney You can use the -m option of the interpreter: python -m timeit '[i for i in range(10000)]'. The timeit module will decide the best number of repetitions and show the mean timing automatically. Anyway using list(range(10000)) is about twice as fast as the list-comprehension.

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.