If we have a list s, is there any difference between calling list(s) versus s[:]? It seems to me like they both create new list objects with the exact elements of s.
4 Answers
In both cases, they should create a (shallow) copy of the list.
Note that there is one corner case (which is hardly worth mentioning) where it might be different...
list = tuple # Don't ever do this!
list_copy = list(some_list) # Oops, actually it's a tuple ...
actually_list_copy = some_list[:]
With that said, nobody in their right mind should ever shadow the builtin list like that.
My advice, use whichever you feel is easier to read and works nicely in the current context.
list(...)makes it explicit that the output is a list and will make a list out of any iterable.something[:]is a common idiom for "give me a shallow copy of this sequence, I don't really care what kind of sequence it is ...", but it doesn't work on arbitrary iterables.
2 Comments
[:] generally outperforms list(). Running a simple timeit test with the list [1, 2, 3] yields 0.9552267117748205 for list() and 0.4996651809098642 for [:]. But like I said, this is somewhat nitpicking; the time difference is negligible in most cases.list(...) requires a global lookup which is somewhat expensive. And the global lookup is required because of the crazy case where a user shadows list. With slicing, the method lookup is done once (during bytecode generation) and is simply invoked on the object. There might be other reasons as well. . . the implementation could probably optimize list.__getitem__ as it can know the memory locations of the objects in the output easily, but list might resort to calling .next() a bunch of times...The short answer is use list(). In google type python [:] then type python list.
If s is a list then there is no difference, but will s always be a list? Or could it be a sequence or a generator?
In [1]: nums = 1, 2, 3
In [2]: nums
Out[2]: (1, 2, 3)
In [3]: nums[:]
Out[3]: (1, 2, 3)
In [4]: list(nums)
Out[4]: [1, 2, 3]
In [7]: strings = (str(x) for x in nums)
In [8]: strings
Out[8]: <generator object <genexpr> at 0x7f77be460550>
In [9]: strings[:]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-358af12435ff> in <module>()
----> 1 strings[:]
TypeError: 'generator' object has no attribute '__getitem__'
In [10]: list(strings)
Out[10]: ['1', '2', '3']
Comments
I didn't realize, but as ventsyv mentioned, s[:] and list(s) both create a copy of s.
Note you can check if an object is the same using is and id() can be used to get the object's memory address to actually see if they are the same or not.
>>> s = [1,2,3]
>>> listed_s = list(s)
>>> id(s)
44056328
>>> id(listed_s) # different
44101840
>>> listed_s is s
False
>>> bracket_s = s[:]
>>> bracket_s is s
False
>>> id(bracket_s)
44123760
>>> z = s # points to the same object in memory
>>> z is s
True
>>> id(z)
44056328
>>>
id(...) id(object) -> integer
Return the identity of an object. This is guaranteed to be unique among simultaneously existing objects. (Hint: it's the object's memory address.)