This question already has answers here:
What's the difference between lists and tuples?
(22 answers)
Closed 21 days ago.
I am trying to understand the difference between tuples and lists
I was trying to use tuples and lists in a piece of my code, and not realising the difference between tuple and list, could someone please tell me difference,
Thanks,
Gops
Both list and tuple are used to store multiple items within a single collection, but there is a key difference tuple is immutable while list is not. Mutability means the ability to modify the object afterward.
# Here we can modify my_list just fine
>>> my_list = ["hello"]
>>> my_list[0] = "world"
>>> print(my_list)
['world']
# But modifying my_tuple leads to an error
>>> my_tuple = ('hello',)
>>> my_tuple[0] = 'world'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> print(my_tuple)
('h', 'e', 'l', 'l', 'o')
You might think to ask why use tuples at all if we can't mutate them. Wouldn't it be better to just have everything be more flexible?
Well, there are things that tuples can do that lists cannot do such as acting as keys for a dictionary. This is a very useful trick for things like points as keys.
>>> my_dict = {("hello", "world"): "foo"}
>>> my_dict[("hello", "world")]
'foo'
If you try to do the same with lists, you get this error. The error message hints at the key difference. Lists cannot be hashed but tuples can be hashed.
>>> my_dict = {["hello", "world"]: "foo"}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Related
This question already has answers here:
How are Python in-place operator functions different than the standard operator functions?
(2 answers)
Closed last month.
Declaration
lst = []
What is the difference between these two lines in python why first line is working another is not
lst += 'a' # this line is working
lst = lst + 'a' # but this line is showing error 'can only concatenate list (not "str") to list'
Not understanding why this two statements are giving different results
on a list += is the same as extend. The argument is seen as an iterable. So it iterates on the string and adds it. But it's not correct in the general case, for instance a string with length > 1.
>>> lst = []
>>> lst += "ab"
>>> lst
['a', 'b'] # not what is expected probably
or adding an integer
>>> lst += 0
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
TypeError: 'int' object is not iterable
On the other hand, in lst + <right term>, the right term is supposed to be a list. Even a tuple would end up with an error.
In your case, the best solution is
lst += ['a']
or
lst.append('a')
which avoids creating a list just to add it to the first one.
As a side note,
lst = lst + other_list
is different from
lst += other_list
as it reassigns lst name on a copy of the old list with added other_list.
Better be aware of that if some other variable is still referencing the old lst
Plus the performance suffers from the copy of the old contents.
This question already has answers here:
Why does += behave unexpectedly on lists?
(9 answers)
Closed 2 years ago.
>>> r = [[]]
>>> r[0] = r[0] + 'abc'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
>>> r[0] += 'abc'
>>> r
[['a', 'b', 'c']]
Could somebody explain why second assignment works but not the first one ?
Why += works and + doesn't work is "that's how its coded". But I haven't figured out any good reason for it. Lets focus simply on list addition
operator magic method list equiv
-------- ------------ ----------
+= (inplace add) __iadd__ list_inplace_concat
+ (add) __add__ list_concat
Inplace Add / list_inplace_concat works on any sequence. Under the covers, python simply calls list.extend which turns the right hand side into an iterator and so works with all sequences
>>> test = []
>>> test += 'abc'
>>> test
['a', 'b', 'c']
Add / list_concat is hardcoded to work only with other lists. The underlying C code uses the internal data structure of the list to copy its elements.
>>> test + 'abc'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
Change the right hand side to a list and it works
>>> test + list('abc')
['a', 'b', 'c', 'a', 'b', 'c']
>>>
list_concat is optimized to use the size of the two lists to know exactly how large the new list needs to be. Then it does member copy at the C structure level. What puzzles me is why there isn't a fallback when the "not a list" condition is detected. The list could be copied and extended.
When run the following code in a scratch file, everything works:
x = [1,1,1]
print(set(x))
> {1}
And yet when I run the following code
class MyClass(object):
def __init__(self):
self.mylist = []
def train(self,vector):
self.mylist.append(vector)
self.mylist = list(set(self.mylist))
I get the error, TypeError: unhashable type: 'list'.
What's the problem here?
When you issue
x = [1,1,1]
set(x)
you are building a set from the elements in x, which is fine because the elements of x are of type int and therefore immutable.
However, mylist is a list of lists (because your vector objects are lists). The problem here is that the lists inside mylist are mutable and therefore cannot be hashed. That's why python refuses to build the set.
You can solve this issue by casting your vector lists to tuple. tuples are immutable and therefore Python has no problem with building a set from a list of tuple objects.
Demo:
>>> lst = [[1,2], [3,4]]
>>> set(lst)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> set(map(tuple, lst))
set([(1, 2), (3, 4)])
This is correct. List is unhashable because it's mutable. Use a tuple instead.
If I have a nested dictionary and I want to make a value into a list and add to it, should I do this
mydict[my_key][my_value] = [mydict[my_key][my_value]].append(new_value)
or this
mydict[my_key][my_value] = list(mydict[my_key][my_value]).append(new_value)
The structure looks like:
{'foo': {'bar': 'hi'}}
and I want:
{'foo': {'bar': ['hi', 'bye']}}
You should not do either one.
list.append works in-place and always returns None. So, mydict[my_key][my_value] will be assigned to None after Python executes either of those lines.
You need to call list.append on its own line:
mydict[my_key][my_value] = [mydict[my_key][my_value]]
mydict[my_key][my_value].append(new_value)
Also, list() and [] are two different things.
Putting mydict[my_key][my_value] in square brackets makes a one-item list where mydict[my_key][my_value] is the item.
Using list() however tells Python to iterate over mydict[my_key][my_value] and collect its items into a list. Moreover, a TypeError will be raised if mydict[my_key][my_value] is not iterable.
Below is a demonstration of what I said above:
>>> tup = (1, 2, 3)
>>> [tup] # Places tup in a list
[(1, 2, 3)]
>>> list(tup) # Makes tup into a list
[1, 2, 3]
>>>
>>> [1]
[1]
>>> list(1) # Integers are not iterable
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>
If you want a list for each dict element, use `defaultdict``
from collections import defaultdict
mydict = defaultdict(list)
mydict[some_key].append(new_value)
Hello my fellow programmers.
I am a fairly new programmer, and now I am facing a great predicament. I am getting the error:
can only assign an iterable
Firstly I don't know what that means.
Secondly I will leave my code for you professionals to critique it:
def num_top(int_lis):
duplic_int_lis = int_lis
int_firs= duplic_int_lis [0]
int_lis[:] = duplic_int_lis [int_firs]
Basically I am trying to find the [0] element in the list and then using that int as an index position to find the integer at that index position.
int_lis[:] = duplic_int_lis [int_firs] means assign all the items of duplic_int_lis [int_firs] to int_lis, so it expects you to pass an iterable/iterator on the RHS.
But in your case you're passing it an non-iterable, which is incorrect:
>>> lis = range(10)
>>> lis[:] = range(5)
>>> lis #all items of `lis` replaced with range(5)
[0, 1, 2, 3, 4]
>>> lis[:] = 5 #Non-iterable will raise an error.
Traceback (most recent call last):
File "<ipython-input-77-0704f8a4410d>", line 1, in <module>
lis[:] = 5
TypeError: can only assign an iterable
>>> lis[:] = 'foobar' #works for any iterable/iterator
>>> lis
['f', 'o', 'o', 'b', 'a', 'r']
As you cannot iterate over an integer, hence the error.
>>> for x in 1: pass
Traceback (most recent call last):
File "<ipython-input-84-416802313c58>", line 1, in <module>
for x in 1:pass
TypeError: 'int' object is not iterable
The RHS of a slice-assignment must be an iterable, not a scalar. Consider slice-deleting and then appending instead.
An iterable is a thing with multiple items that you can iterate through (for example: take the 1st value do something, then the 2nd do something, etc...) Lists, dictionaries, tuples, strings have several items in them and can be used as iterables. As a counterexample: number types don't qualify as iterable.
Remember that computers count from #0 so: if you want the first value of a list you can use
my_list[0]
before you go further I would suggest watching this video about looping. https://www.youtube.com/watch?v=EnSu9hHGq5o