When [] is passed as the second argument to dict.fromkeys(), all values in the resulting dict will be the same list object.
In Python 2.7 or above, use a dict comprehension instead:
Copydata = {k: [] for k in range(2)}
In earlier versions of Python, there is no dict comprehension, but a list comprehension can be passed to the dict constructor instead:
Copydata = dict([(k, []) for k in range(2)])
In 2.4-2.6, it is also possible to pass a generator expression to dict, and the surrounding parentheses can be dropped:
Copydata = dict((k, []) for k in range(2))
Answer from Sven Marnach on Stack OverflowWhen [] is passed as the second argument to dict.fromkeys(), all values in the resulting dict will be the same list object.
In Python 2.7 or above, use a dict comprehension instead:
Copydata = {k: [] for k in range(2)}
In earlier versions of Python, there is no dict comprehension, but a list comprehension can be passed to the dict constructor instead:
Copydata = dict([(k, []) for k in range(2)])
In 2.4-2.6, it is also possible to pass a generator expression to dict, and the surrounding parentheses can be dropped:
Copydata = dict((k, []) for k in range(2))
Try using a defaultdict instead:
Copyfrom collections import defaultdict
data = defaultdict(list)
data[1].append('hello')
This way, the keys don't need to be initialized with empty lists ahead of time. The defaultdict() object instead calls the factory function given to it, every time a key is accessed that doesn't exist yet. So, in this example, attempting to access data[1] triggers data[1] = list() internally, giving that key a new empty list as its value.
The original code with .fromkeys shares one (mutable) list. Similarly,
Copyalist = [1]
data = dict.fromkeys(range(2), alist)
alist.append(2)
print(data)
would output {0: [1, 2], 1: [1, 2]}. This is called out in the dict.fromkeys() documentation:
All of the values refer to just a single instance, so it generally doesnโt make sense for value to be a mutable object such as an empty list.
Another option is to use the dict.setdefault() method, which retrieves the value for a key after first checking it exists and setting a default if it doesn't. .append can then be called on the result:
Copydata = {}
data.setdefault(1, []).append('hello')
Finally, to create a dictionary from a list of known keys and a given "template" list (where each value should start with the same elements, but be a distinct list), use a dictionary comprehension and copy the initial list:
Copyalist = [1]
data = {key: alist[:] for key in range(2)}
Here, alist[:] creates a shallow copy of alist, and this is done separately for each value. See How do I clone a list so that it doesn't change unexpectedly after assignment? for more techniques for copying the list.
Why is it common in python to make an empty list or dict first?
Python: Adding an empty list as value to a dictionary - Stack Overflow
How to remove empty dictionary value from list?
Yes the quotes (empty string) are considered values and you would use an if statement. Probably what I would suggest is a list comprehension:
[d for d in mylist if d['name']]
This creates a new list with each dictionary value in there if the value corresponding to the key 'name' is not an empty string. The empty string is a Falsey value in Python, so instead of checking if d['name'] != '' (which is also totally valid) you can just ask if d['name'].
python - Create a list of empty dictionaries - Stack Overflow
Something I've never understood with python is why it is so common for an empty list to be created and then populated with something in a subsequent (or even more common next) line:
my_list = [] my_list = [i for i in range(1, 21)]
Obviously this is a really really toy example, but I'm consistently finding this in "production" code in multiple places. Is it pythonic? It's basically pure duplication so I doubt it. Is it some hacky "optimisation"? Is it a side effect of the code priorly being a for loop, then turned to a list comprehension but not tidied up right?
I honestly just feel ike I'm missing something key, with the amount of times and variety of places I see this pattern.
I have a list with dictionary objects in them like so:
[{'name':'test1'},{'name':''},{'name':'test2'}]How do I check if the list has a empty dictionary value and remove said value so the new list looks like this:
[{'name':'test1'},{'name':'test2'}]do I need an if statement for this? are the quotes considered values in the dictionary?
Yes the quotes (empty string) are considered values and you would use an if statement. Probably what I would suggest is a list comprehension:
[d for d in mylist if d['name']]
This creates a new list with each dictionary value in there if the value corresponding to the key 'name' is not an empty string. The empty string is a Falsey value in Python, so instead of checking if d['name'] != '' (which is also totally valid) you can just ask if d['name'].
An alternative to creating a new list is to iterate backwards through the original list and selectively delete elements:
for i in range(len(mylist) - 1, -1, -1):
if mylist[i]["name"] == "":
del mylist[i]
This is useful for cases where you have other objects that refer to the original list, since it retains the original list (whereas binding the same variable name to a new list doesn't replace the original list in memory). This might be getting away from your original question, but here's an example to show what I mean:
>>> x = [1, 2, 3] # original list
>>> y = [x, 'a', 'b'] # another object that refers to the original list
>>> print(y)
[[1, 2, 3], 'a', 'b']
>>> x.append(4) # modify the original list
>>> print(y) # demonstrate that the change is reflected in the object that references the list
[[1, 2, 3, 4], 'a', 'b']
>>> del x[1] # modify the original list by deleting an element
>>> print(x)
[1, 3, 4]
>>> print(y) # again, show that the change is reflected in the other object
[[1, 3, 4], 'a', 'b']
>>> x = [num for num in x if num > 2] # bind variable name x to a new list using a comprehension
>>> print(x)
[3, 4]
>>> print(y) # show that the reference in y still refers to the old list, which is no longer bound to a variable
[[1, 3, 4], 'a', 'b']
Just something to keep in mind.