I am trying to create a Python dictionary from a stored list. This first method works
>>> myList = []
>>> myList.append('Prop1')
>>> myList.append('Prop2')
>>> myDict = dict([myList])
However, the following method does not work
>>> myList2 = ['Prop1','Prop2','Prop3','Prop4']
>>> myDict2 = dict([myList2])
ValueError: dictionary update sequence element #0 has length 3; 2 is required
So I am wondering why the first method using append works but the second method doesn't work? Is there a difference between myList and myList2?
Edit
Checked again myList2 actually has more than two elements. Updated second example to reflect this.
You're doing it wrong.
The dict() constructor doesn't take a list of items (much less a list containing a single list of items), it takes an iterable of 2-element iterables. So if you changed your code to be:
myList = []
myList.append(["mykey1", "myvalue1"])
myList.append(["mykey2", "myvalue2"])
myDict = dict(myList)
Then you would get what you expect:
>>> myDict
{'mykey2': 'myvalue2', 'mykey1': 'myvalue1'}
The reason that this works:
myDict = dict([['prop1', 'prop2']])
{'prop1': 'prop2'}
Is because it's interpreting it as a list which contains one element which is a list which contains two elements.
Essentially, the dict constructor takes its first argument and executes code similar to this:
for key, value in myList:
print key, "=", value
Related
This question already has answers here:
How do I initialize a dictionary of empty lists in Python?
(7 answers)
Closed 2 years ago.
I came across this behavior that surprised me in Python 2.6 and 3.2:
>>> xs = dict.fromkeys(range(2), [])
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: [1]}
However, dict comprehensions in 3.2 show a more polite demeanor:
>>> xs = {i:[] for i in range(2)}
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: []}
>>>
Why does fromkeys behave like that?
Your Python 2.6 example is equivalent to the following, which may help to clarify:
>>> a = []
>>> xs = dict.fromkeys(range(2), a)
Each entry in the resulting dictionary will have a reference to the same object. The effects of mutating that object will be visible through every dict entry, as you've seen, because it's one object.
>>> xs[0] is a and xs[1] is a
True
Use a dict comprehension, or if you're stuck on Python 2.6 or older and you don't have dictionary comprehensions, you can get the dict comprehension behavior by using dict() with a generator expression:
xs = dict((i, []) for i in range(2))
In the first version, you use the same empty list object as the value for both keys, so if you change one, you change the other, too.
Look at this:
>>> empty = []
>>> d = dict.fromkeys(range(2), empty)
>>> d
{0: [], 1: []}
>>> empty.append(1) # same as d[0].append(1) because d[0] references empty!
>>> d
{0: [1], 1: [1]}
In the second version, a new empty list object is created in every iteration of the dict comprehension, so both are independent from each other.
As to "why" fromkeys() works like that - well, it would be surprising if it didn't work like that. fromkeys(iterable, value) constructs a new dict with keys from iterable that all have the value value. If that value is a mutable object, and you change that object, what else could you reasonably expect to happen?
To answer the actual question being asked: fromkeys behaves like that because there is no other reasonable choice. It is not reasonable (or even possible) to have fromkeys decide whether or not your argument is mutable and make new copies every time. In some cases it doesn't make sense, and in others it's just impossible.
The second argument you pass in is therefore just a reference, and is copied as such. An assignment of [] in Python means "a single reference to a new list", not "make a new list every time I access this variable". The alternative would be to pass in a function that generates new instances, which is the functionality that dict comprehensions supply for you.
Here are some options for creating multiple actual copies of a mutable container:
As you mention in the question, dict comprehensions allow you to execute an arbitrary statement for each element:
d = {k: [] for k in range(2)}
The important thing here is that this is equivalent to putting the assignment k = [] in a for loop. Each iteration creates a new list and assigns it to a value.
Use the form of the dict constructor suggested by #Andrew Clark:
d = dict((k, []) for k in range(2))
This creates a generator which again makes the assignment of a new list to each key-value pair when it is executed.
Use a collections.defaultdict instead of a regular dict:
d = collections.defaultdict(list)
This option is a little different from the others. Instead of creating the new list references up front, defaultdict will call list every time you access a key that's not already there. You can there fore add the keys as lazily as you want, which can be very convenient sometimes:
for k in range(2):
d[k].append(42)
Since you've set up the factory for new elements, this will actually behave exactly as you expected fromkeys to behave in the original question.
Use dict.setdefault when you access potentially new keys. This does something similar to what defaultdict does, but it has the advantage of being more controlled, in the sense that only the access you want to create new keys actually creates them:
d = {}
for k in range(2):
d.setdefault(k, []).append(42)
The disadvantage is that a new empty list object gets created every time you call the function, even if it never gets assigned to a value. This is not a huge problem, but it could add up if you call it frequently and/or your container is not as simple as list.
I am looking for a simple way to compare the content of multiple lists and find the one with the fewest variables.
Then I want to set the new variable to be added to that list.
Example:
list1 = [1,5,7,12,4,8]
list2 = [3,2,9,11,14,6,10]
list3 = [13,15,16]
In this I would want it to find list3 to be the shortest and append the new value to it.
Due to pythons min, max, and sort's key keyword argument this is fairly simple to do in python
min([list1, list2, list3..], key = len).append(item)
key corresponds to the function applied to each element and whose result is used for comparison in both min and max. in this case the function len (which retrieves the length of sequence objects like list and tuple and any class that defines __len__ ) is used.
from min.
The key argument specifies a one-argument ordering function like that used for list.sort()
from list.sort()
key specifies a function of one argument that is used to extract a comparison key from each list element (for example, key=str.lower).
example
>>> x = [11231]
>>> y = [1,2,3,4,5]
>>> z = [1,2,3,4,1,1]
>>> min([x,y,z], key = len)
[11231]
You could write a small function that checks the len of each list, then append to that list.
def add_to_shortest(lists, item):
min(lists, key = lambda i: len(i)).append(item)
For example
>>> add_to_shortest([list1, list2, list3], 5)
>>> list3
[13, 15, 16, 5]
This question already has answers here:
How do I initialize a dictionary of empty lists in Python?
(7 answers)
Closed 2 years ago.
I came across this behavior that surprised me in Python 2.6 and 3.2:
>>> xs = dict.fromkeys(range(2), [])
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: [1]}
However, dict comprehensions in 3.2 show a more polite demeanor:
>>> xs = {i:[] for i in range(2)}
>>> xs
{0: [], 1: []}
>>> xs[0].append(1)
>>> xs
{0: [1], 1: []}
>>>
Why does fromkeys behave like that?
Your Python 2.6 example is equivalent to the following, which may help to clarify:
>>> a = []
>>> xs = dict.fromkeys(range(2), a)
Each entry in the resulting dictionary will have a reference to the same object. The effects of mutating that object will be visible through every dict entry, as you've seen, because it's one object.
>>> xs[0] is a and xs[1] is a
True
Use a dict comprehension, or if you're stuck on Python 2.6 or older and you don't have dictionary comprehensions, you can get the dict comprehension behavior by using dict() with a generator expression:
xs = dict((i, []) for i in range(2))
In the first version, you use the same empty list object as the value for both keys, so if you change one, you change the other, too.
Look at this:
>>> empty = []
>>> d = dict.fromkeys(range(2), empty)
>>> d
{0: [], 1: []}
>>> empty.append(1) # same as d[0].append(1) because d[0] references empty!
>>> d
{0: [1], 1: [1]}
In the second version, a new empty list object is created in every iteration of the dict comprehension, so both are independent from each other.
As to "why" fromkeys() works like that - well, it would be surprising if it didn't work like that. fromkeys(iterable, value) constructs a new dict with keys from iterable that all have the value value. If that value is a mutable object, and you change that object, what else could you reasonably expect to happen?
To answer the actual question being asked: fromkeys behaves like that because there is no other reasonable choice. It is not reasonable (or even possible) to have fromkeys decide whether or not your argument is mutable and make new copies every time. In some cases it doesn't make sense, and in others it's just impossible.
The second argument you pass in is therefore just a reference, and is copied as such. An assignment of [] in Python means "a single reference to a new list", not "make a new list every time I access this variable". The alternative would be to pass in a function that generates new instances, which is the functionality that dict comprehensions supply for you.
Here are some options for creating multiple actual copies of a mutable container:
As you mention in the question, dict comprehensions allow you to execute an arbitrary statement for each element:
d = {k: [] for k in range(2)}
The important thing here is that this is equivalent to putting the assignment k = [] in a for loop. Each iteration creates a new list and assigns it to a value.
Use the form of the dict constructor suggested by #Andrew Clark:
d = dict((k, []) for k in range(2))
This creates a generator which again makes the assignment of a new list to each key-value pair when it is executed.
Use a collections.defaultdict instead of a regular dict:
d = collections.defaultdict(list)
This option is a little different from the others. Instead of creating the new list references up front, defaultdict will call list every time you access a key that's not already there. You can there fore add the keys as lazily as you want, which can be very convenient sometimes:
for k in range(2):
d[k].append(42)
Since you've set up the factory for new elements, this will actually behave exactly as you expected fromkeys to behave in the original question.
Use dict.setdefault when you access potentially new keys. This does something similar to what defaultdict does, but it has the advantage of being more controlled, in the sense that only the access you want to create new keys actually creates them:
d = {}
for k in range(2):
d.setdefault(k, []).append(42)
The disadvantage is that a new empty list object gets created every time you call the function, even if it never gets assigned to a value. This is not a huge problem, but it could add up if you call it frequently and/or your container is not as simple as list.
I am trying to add to a list that is a value of a key in two different (operations?). Below is an example:
item['foo'] = ["blah"]
item['foo'] = ["garble"]
where item is a dictionary and foo is a key. Then if I print foo I get:
["garble"]
when I want
["blah", "garble"]
How do I get the end result I want?
EDIT: formating
Since you want the value to be a list, you should append to item['foo'] like this:
item = {}
item['foo'] = ["blah"]
item['foo'].append("garble")
print(item)
which prints out:
{'foo': ['blah', 'garble']}
If garble is a list, for example something like garble = ["blah2"], you can do list merging like this:
item = {}
item['foo'] = ["blah"]
garble = ["blah2"]
item['foo'] += garble
print item
Which in turn prints out:
{'foo': ['blah', 'blah2']}
You are overwriting the dictionary value instead of appending to it, try:
item['foo'] = ['blah']
item['foo'].append('garble')
What you are doing with the code shown is first assigning the value ['blah'] to the key 'foo', and then, in the next step, assigning the value ['garble'] to the key 'foo'. A key can only be assigned to one value (and by "value", we mean any type, be it an integer, a string, a list, a tuple, etc.), so the second assignment overwrites the first. What you want is for the key 'foo' be assigned to the list ["blah", "garble"]. The list is one value. This can be done in one step like this:
item['foo'] = ["blah", "garble"]
or, if, for some reason, you want to create a key value pair where the value is a list, and then add an item to that list later, this is how you would do it:
item['foo'] = ['blah']
item['foo'].append('garble')
The first line assigns the list ['blah'] to the key 'foo'. The second line retrieves the value assigned to the key 'foo' from the dictionary item, applies the list method .append() to it (which will ONLY work if the value retrieved from the dictionary with the key 'foo' IS in fact a list!), and then appends to that list the string 'garble'. The result is:
>>> item['foo']
['blah', 'garble']
Do NOT do this:
item['foo'].append(['garble'])
or you will end up with the second element of this list another list, like this:
['blah', ['garble']]
To get the values of the key:
>>> item["foo"] = ["bar"] # bar is the value
If bar is a list, you can use all of the methods that are already associated with it. Here we use append.
>>> item["foo"].append("meh")
>>> item["foo"]
["bar", "meh"]
Of course, if you want to add a list (and have it be "merged"), you the extend method.
>>> item["foo"].extend(["gar", "ble"])
>>> item["foo"]
["bar", "meh", "gar", "ble"]
If you don't use extend there, you'll have a nested list:
["bar", "meh", ["gar", "ble"]]
I would use collections.defaultdict in combination with list.extend:
>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> dd[1].extend([2]) # You can now do stuff like this without initialization
>>> dd[1].extend((3, 4)) # No worries, hakuna matata style
>>> dd[1]
[2, 3, 4]
In my opinion, this makes the code very simple and clean.
You can also use list.append to add a single element to the list instead of all the elements of an iterable:
>>> dd[1].append(5)
>>> dd[1]
[2, 3, 4, 5]
Close you just need to append it
item = dict()
item['foo'] = ["blah"]
#above sets key foo to list value blah
#either of below appends a new value to the foo's list
item['foo'] += ["garble"]
#or item['foo'].append("garble")
#note if this method is used list notation is needed to stop interpretation
# of each character. So I'd use append but wanted to show how close you were
print item
#outputs: {'foo': ['blah', 'garble']}
#PythonNoob see the comment if += works for you it works but .append would be the preferred method and I'd also look at #Zizouz212 answer as the extend feature is a useful addition.
You can use setdefault. It would try to look for 'foo' at first; if it cannot find it, setdefault would add 'foo' to item dictionary, with corresponding value as [], and would also return the reference to this value. To this returned value, you can append entries from vals list.
If setdefault is able to find the key 'foo' in the dictionary, it simply returns the corresponding value for it, which would again be a list.
item = {}
vals = ['blah', 'garble']
for x in vals:
item.setdefault('foo', []).append(x)
print item['foo'] # print ['blah', 'garble']
>>> item = {}
>>> item['foo'] = ["blah"]
>>> item['foo'].append("garble")
>>> item
{'foo': ['blah', 'garble']}
>>>
I am running into this situation while using chained methods in python.
Suppose, I have the following code
hash = {}
key = 'a'
val = 'A'
hash[key] = hash.get(key, []).append(val)
The hash.get(key, []) returns a [] and I was expecting that dictionary would be {'a': ['A']}. However the dictionary is set as {'a': None}.
On looking this up further, I realised that this was occurring due to python lists.
list_variable = []
list_variable.append(val)
sets the list_variable as ['A']
However, setting a list in the initial declaration
list_variable = [].append(val)
type(list_variable)
<type 'NoneType'>
What is wrong with my understanding and expectation that list_variable should contain ['A']
Why are the statements behaving differently?
The .append() function alters the list in place and thus always returns None. This is normal and expected behaviour. You do not need to have a return value as the list itself has already been updated.
Use the dict.setdefault() method to set a default empty list object:
>>> hash = {}
>>> hash.setdefault('a', []).append('A')
>>> hash
{'a': ['A']}
You may also be interested in the collections.defaultdict class:
>>> from collections import defaultdict
>>> hash = defaultdict(list)
>>> hash['a'].append('A')
>>> hash
defaultdict(<type 'list'>, {'a': ['A']})
If you want to return a new list with the extra item added, use concatenation:
lst = lst + ['val']
append operates in-place. However you can utilize setdefault in this case:
hash.setdefault(key, []).append(val)