Making a list of a "master" dictionary - python

I have a prototype dictionary that i want to use as a basis for appending to a list.
I want to change 1 or more values in the dictionary then capture it as an element of a list.
My question is this; is there any other recommended method for doing this short of using deepcopy().
I know this doesn't work properly:
l = []
d = {}
d['key'] = 4
l.append(d)
d['key'] = 5
l.append(d)
it gives:
l = [{'key': 5}, {'key': 5}]
it also didn't seem to work using a simply copy()

You are appending a reference to the same object to both lists, so when you change the value of "key", you change it in both lists. You need to make a copy of the dictionary before appending if you want a separate reference, using the dict.copy function:
l = []
d = {}
d['key'] = 4
l.append(d.copy())
d['key'] = 5
l.append(d.copy())
If you need a deep copy, you can use the copy library:
import copy
l = []
d = {}
d['key'] = 4
l.append(copy.deepcopy(d))
d['key'] = 5
l.append(copy.deepcopy(d))

copy should work.
l = []
d = {}
d['key'] = 4
l.append(d)
d = d.copy()
d['key'] = 5
l.append(d)
Result:
[{'key': 4}, {'key': 5}]

Related

Looping through all keys in a tuple of dictionaries

I have created the following dictionaries and a tuple:
dict1 = {'a':1,'b':2}
dict2 = {'c':3,'d':4}
dict3 = {'e':5,'f':6}
tuple_purse = dict1, dict2, dict3
I want to loop and print out all the keys in all the dictionaries in tuple_purse. I tried the following code:
for key in tuple_purse:
print(key)
for key,value in tuple_purse:
print(key)
And got the following output:
{'a': 1, 'b': 2}
{'c': 3, 'd': 4}
{'e': 5, 'f': 6}
a
c
e
Is there a way to loop through all the keys: a,b,c,d,e,f elegantly?
Thanks.
You can use chain from itertools.
Make an iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted. Used for treating consecutive sequences as a single sequence
import itertools
dict1 = {'a':1,'b':2}
dict2 = {'c':3,'d':4}
dict3 = {'e':5,'f':6}
tuple_purse = dict1, dict2, dict3
for x in itertools.chain.from_iterable(tuple_purse):
print(x)
A simple quick double for perhaps? Do you need something more?
for ddict in tuple_purse:
for key in ddict:
print(key)
You can try this:
dict1 = {'a':1,'b':2}
dict2 = {'c':3,'d':4}
dict3 = {'e':5,'f':6}
tuple_dict = {**dict1, **dict2, **dict3}
for i in tuple_dict:
print(i, tuple_dict[i])
Note that for the solution above, the code will fail if there are multiple keys of the same name in two or more of the dicts.
Output:
a 1
b 2
c 3
d 4
e 5
f 6
Python2 solution
new_list = [dict1, dict2, dict3]
for d in new_list:
for k in d:
print k, d[k]
Output:
a 1
b 2
c 3
d 4
e 5
f 6

One liner if an index doesnt exists

For a lot of objects before calling .append() I do something like:
if not d.get('turns'):
d['turns'] = []
Is there a oneliner in Python to do this?
After some answers, here's my kind of code:
d = json.loads(str(self.data))
if not d.get('turns'):
d['turns'] = []
d['turns'].append({
'date': time_turn,
'data': data
})
You can use defaultdict:
from collections import defaultdict
d = defaultdict(list)
d['turns'] # []
Other option is to use setdefault:
d.setdefault('turns', []) # []
d.setdefault('turns', 'foo') # []
UPDATE Given the full code you could either write
d = defaultdict(list, json.loads(str(self.data)))
d['turns'].append({'date': time_turn, 'data': data})
or
d = json.loads(str(self.data))
d.setdefault('turns', []).append({'date': time_turn, 'data': data})
Is there a oneliner in Python to do this?
Yes
d.setdefault('turns', [])
Demo:
>>> d = {}
>>> d.setdefault('turns', [])
[] # the inserted value is also returned
>>> d
{'turns': []}
If the key is found, setdefault behaves like get:
>>> d['turns'].append(1)
>>> d.setdefault('turns', 'irrelevant')
[1]
depending on if the get is standard, it likely has the option to specify a default return if the item is not found, so
d.get('turns', [])
will give you the value if it exists, or [] if it doesn't.
Well, you can "oneline" it using :
d['turns'] = [] if not d.get('turns')

Create new empty lists from items within a Python list?

my_list = ['c1','c2','c3']
Is there anyway to create a certain amount of new lists based on items inside of a list?
Result would be:
c1 = []
c2 = []
c3 = []
You can do that using globals():
>>> my_list = ['c1','c2','c3']
>>> for x in my_list:
... globals()[x] = []
...
>>> c1
[]
>>> c2
[]
>>> c3
[]
But it's better to use a dict here:
>>> dic = {item : [] for item in my_list}
>>> dic
{'c2': [], 'c3': [], 'c1': []}
Instead of creating new global variables using the names from your list, I would suggest using a dictionary:
my_list = ['c1', 'c2', 'c3']
my_dict = {k: [] for k in my_list}
Then to access one of those lists you could use something like my_dict['c1'] or my_dict['c2'].
Another solution would be to add the new lists as attributes to some object or module. For example:
lists = type('Lists', (object,), {k: [] for k in my_list})
After which you could access your lists using lists.c1, lists.c2, etc.
In my opinion both of these methods are cleaner than modifying globals() or locals() and they give you very similar behavior.
Note that if you are on Python 2.6 or below you will need to replace the dictionary comprehensions with dict((k, []) for k in my_list).

Trying to create new dictionaries through iteration

I'm not even able to properly search google for it, but here goes:
a = {}
b = {}
c = [a, b]
for d in c:
d['ID'] = d
print c
returns:
[{'ID': {...}}, {'ID': {...}}]
why isn't it:
[{'ID': a}, {'ID': b}]
Let's step through this:
a = {}
b = {}
c = [a, b]
So far, so good.
for d in c:
d['ID'] = d
We can unroll this to:
d = c[0]
d['ID'] = d
d = c[1]
d['ID'] = 1
And expand that to:
d = a
d['ID'] = d
d = b
d['ID'] = d
Now substitute:
a['ID'] = a
b['ID'] = a
So, let's forget about the loop for a second and look at what that does:
>>> a = {}
>>> a['ID'] = a
>>> a
{'ID': {...}}
In other words, you're making each dict recursively contain a copy of itself, under the key ID. How would you expect this to be printed?
So, the obvious thing to do is to try to print the whole dictionary:
{'ID': {'ID': {'ID': { …
But this would be an infinitely-long string, and Python would run out of stack space before reaching infinity. So it needs to truncate it somehow.
It can't print this:
{'ID': a}
Because a is just a name that happens to be bound to the dict, just like d is at the time. In fact, the loop doesn't even know that a is bound to that at the time; it knows that d is. But even if it did know, the result would be wrong. Think about this:
>>> e = a
>>> a = 0
>>> e
???
So, the obvious answer is to use an ellipsis (kind of like I did in the human-readable version) to represent "and so on".
a is a dictionary.
b is a dictionary.
c is a list of two dictionaries (not "two names" or "two variables").
Another socratic explanation:
If it would return [{'ID': a}, {'ID': b}], values displayed as a and b would be of which type?
Consider what the loop is doing:
a = {}
b = {}
c = [a, b]
for d in c:
d['ID'] = d
d will be either a or b, such that
a['ID'] = a
b['ID'] = b
but recall a and b are {}, the dics themselves. as a result, your assigning ['ID'] to the dic itself, creating a loop. When you
print(c)
you get [{'ID': {...}}, {'ID': {...}}] because the value of the key is the dic itself and not the variable representation of it, hence you get {...} to reflect the nature of the loop.
Note how after this a['ID']['ID'], or even a ['ID']['ID']['ID']['ID'] is {'ID': {...}}, because the value of the key is the dic itself, not the variable pointing to it.
for d in c:
d['ID'] = d
should be
c = [{'ID': d} for d in c]
Your code is adding the ID element to each of the dicts in c. That means a = {'ID': a} after your code has run. It contains a reference to itself.
My snippet generates a new dict with a property 'ID' containing a value from c.

Python append to a value in dictionary

I have a following dictionary:
d = {'key':{'key2':[]}}
Is there any way to append to d['key']?
I want to get:
d = {'key':{'key2':[], 'key3':[]}}
d['key'] = ['key3'] apparently does not produce the desired outcome..
I know I can do
d = {'key': [{'key2': []}]}
and then append to d['key'] in a loop, but I am trying to avoid that..
You're looking for
d['key']['key3'] = []
Alternate solution.
d['key'].update({'key3':[]})
Since d["key"] is a dictionary, you can set keys in this dictionary as usual:
e = d["key"]
e["key3"] = []
or simply
d["key"]["key3"] = []
Why not trying:
d['key']['key3'] = []
That should work.

Categories