Is python's queue.Queue.put() method asynchronous? [duplicate] - multithreading

This question already has answers here:
How to copy a dictionary and only edit the copy
(23 answers)
Closed 5 years ago.
If I run a thread with the following function as the worker,
q = queue.Queue()
def worker():
while True:
t = {}
for i in range(3):
t['a'] = i
q.put(t)
the queue is populated with dictionaries that are all the same, i.e., {'a': 2} instead of the sequence {'a': 0}, {'a': 1}, {'a': 2}. I assume this is because the put() method runs after the for loop has finished and the last value of i was 2. Am I interpreting that right?
Now, if I move the instantiation of the dictionary inside the for loop,
def worker():
while True:
for i in range(3):
t = {'a': i}
q.put(t)
the queue is populated with the desired sequence. My interpretation is that in the first instance, I create a dictionary object in memory, then begin a for loop and reassign its value 3 times but the put() calls happen after the loop has finished. In the second instance, I create a new dictionary object every iteration of the for loop and so when the put() calls occur after the loop, they access 3 distinct instances of the dictionary with their own key-value pairs.
Can anyone shed some light on what's happening behind the curtain here?

Am I interpreting that right?
You observe such behavior because you’re modifying the same object all the time
Lets put aside queues / threads and run a simplified equivalent of your code with some prints to understand what’s happening
t = {}
l = []
for i in range(3):
t['a'] = i
l.append(t)
print(l)
t['a'] = 20
print(l)
print(map(id, l))
[{'a': 2}, {'a': 2}, {'a': 2}]
[{'a': 20}, {'a': 20}, {'a': 20}]
# they are all the same!
[4474861840, 4474861840, 4474861840]
So it has nothing to do we threads/queues - you’re just adding the same object 3 times.
Now, if I move the instantiation of the dictionary inside the for loop
In this case you create a new object every time like in the following code:
l = []
for i in range(3):
t = {}
t['a'] = i
l.append(t)
print(l)
t['a'] = 20
print(l)
print(map(id, l))
[{'a': 0}, {'a': 1}, {'a': 2}]
[{'a': 0}, {'a': 1}, {'a': 20}]
# they are all different!
[4533475600, 4533502592, 4533502872]
So no magic here
back to your question
This is what could be of interest for you: “Is python’s queue.Queue.put() thread safe?” meaning that the global variable q could be accessed by multiple concurrent threads safely.
The answer is yes - it is thread safe
The Queue module implements multi-producer, multi-consumer queues. It
is especially useful in threaded programming when information must be
exchanged safely between multiple threads. The Queue class in this
module implements all the required locking semantics

In the first example, you are putting the same dict into the queue three times. This has nothing to do with the queue. You would find the same behaviour with list.append.

Related

I append dictionary to a list, while printing i get only the last appended thing in the dictionary of the list

class one:
def __init__(self,id,d):
self.id=id
self.d=d
def printfun(self):
for i in l:
print(i.id,i.d)
l=[]
d={}
for i in range(2):
id=int(input())
d["a"]=int(input())
d["b"]=int(input())
o=one(id,d)
l.append(o)
o.printfun()
and my output is:
100
1
2
101
3
4
100 {'a': 3, 'b': 4}
101 {'a': 3, 'b': 4}
I append dictionary to a list, while printing i get only the last appended thing in the dictionary of the list. How to get all the dictionary i have appended in the list, and why i am not getting first dictionary i had appended in the list.
You need to append a new dictionary to the list, because otherwise you're appending a reference to the old list that has modified values.
Python never implicitly copies objects. When you set dict2 = dict1, you are making them refer to the same exact dict object, so when you mutate it, all references to it keep referring to the object in its current state.
https://stackoverflow.com/a/2465932/4361039
l=[]
for i in range(2):
id=int(input())
a=int(input())
b=int(input())
o=one(id, {"a": a, "b": b})
l.append(o)
o.printfun()

Python defining iterators for dictionary comprehension for a class

I want to check with someone if I defined the iteration function properly. To explain, please consider the following example:
x=[{'n':'foo', 'a': [1,2,3], 'b':[2,3,5]}, {'n':'baz','a':[4,5,6], 'b':[7,8,9]},
{'n':'foo', 'a': [4,3,4], 'b':[1,5,6]}, {'n':'bar','a':[1,2,2], 'b':[2,5,6]}]
quick_dict = {key['n']: [sample['a'] for sample in x if sample['n']==key['n']] for key in x}
This works as expected and outputs:
{'foo': [[1, 2, 3], [4, 3, 4]], 'baz': [[4, 5, 6]], 'bar': [[1, 2, 2]]}
I am trying to do something similar for a class I defined using the __next__ and __iter__ methods. The class instance has many functions and attributes but for the purpose of this question, only the attribute samples is important because it is a list of dictionaries exactly as in the above example. I defined the methods as follows:
def __next__(self):
if self.itercounter < len(self.samples)-1:
self.itercounter +=1
return self.samples[self.itercounter]
else:
raise StopIteration
def __iter__(self):
self.itercounter = -1
return self
This seems to work for list comprehensions, but it fails for dictionary comprehensions.
If I do:
quick_dict = {key['Name']: [sample['CM'] for sample in data if sample['Name'] == key['Name']]
for key in data.samples}
then it works because it is directly accessing the list of dictionaries and it knows what to do. On the other hand if I do
quick_dict = {key['Name']: [sample['CM'] for sample in data if sample['Name'] == key['Name']]
for key in data}
then it is going through my functions, and it doesn't work. It just returns a dictionary with a single key. Here 'CM' is just a key like 'a' in the example.
What am I doing wrong in my definition of __iter__ and __next__?
Your second definition of quick_dict iterates over data with for sample in data while already iterating over it with for key in data. However, your __iter__ and __next__ implementation uses a single instance attribute to control iteration, meaning that nested iteration over data won't work because the second (nested) call to __iter__ resets the counter. To support nested iteration, eliminate __next__ and have __iter__ return a generator instead:
def __iter__(self):
i = -1
while i < len(self.samples)-1:
i += 1
yield self.samples[i]

get() inside dict composition

New to python/programming, and working on dict composition. (python 3)
Is it possible to use the get method inside of a dict composition on the dict you're creating?
e.g. d = {key: d.get(key,0) + 1 for key in some_list}
Feel free to provide a better way of accomplishing the example, but I'm really interested in understanding if using get on the dict you're creating is possible/valid.
Nope, not possible. If you want a dict of counts, use the collections.Counter dict subclass:
import collections
counts = collections.Counter(some_list)
Python has dedicated class for handing this kind of problems - collections.Counter.
import collections
seq = ['a', 'b', 'b', 'c']
d = collections.Counter(seq) # Counter({'b': 2, 'a': 1, 'c': 1})

How to loop through python dictionaries [duplicate]

d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(key, 'corresponds to', d[key])
How does Python recognize that it needs only to read the key from the dictionary? Is key a special keyword, or is it simply a variable?
key is just a variable name.
for key in d:
will simply loop over the keys in the dictionary, rather than the keys and values. To loop over both key and value you can use the following:
For Python 3.x:
for key, value in d.items():
For Python 2.x:
for key, value in d.iteritems():
To test for yourself, change the word key to poop.
In Python 3.x, iteritems() was replaced with simply items(), which returns a set-like view backed by the dict, like iteritems() but even better.
This is also available in 2.7 as viewitems().
The operation items() will work for both 2 and 3, but in 2 it will return a list of the dictionary's (key, value) pairs, which will not reflect changes to the dict that happen after the items() call. If you want the 2.x behavior in 3.x, you can call list(d.items()).
It's not that key is a special word, but that dictionaries implement the iterator protocol. You could do this in your class, e.g. see this question for how to build class iterators.
In the case of dictionaries, it's implemented at the C level. The details are available in PEP 234. In particular, the section titled "Dictionary Iterators":
Dictionaries implement a tp_iter slot that returns an efficient
iterator that iterates over the keys of the dictionary. [...] This
means that we can write
for k in dict: ...
which is equivalent to, but much faster than
for k in dict.keys(): ...
as long as the restriction on modifications to the dictionary
(either by the loop or by another thread) are not violated.
Add methods to dictionaries that return different kinds of
iterators explicitly:
for key in dict.iterkeys(): ...
for value in dict.itervalues(): ...
for key, value in dict.iteritems(): ...
This means that for x in dict is shorthand for for x in
dict.iterkeys().
In Python 3, dict.iterkeys(), dict.itervalues() and dict.iteritems() are no longer supported. Use dict.keys(), dict.values() and dict.items() instead.
Iterating over a dict iterates through its keys in no particular order, as you can see here:
(This is no longer the case in Python 3.6, but note that it's not guaranteed behaviour yet.)
>>> d = {'x': 1, 'y': 2, 'z': 3}
>>> list(d)
['y', 'x', 'z']
>>> d.keys()
['y', 'x', 'z']
For your example, it is a better idea to use dict.items():
>>> d.items()
[('y', 2), ('x', 1), ('z', 3)]
This gives you a list of tuples. When you loop over them like this, each tuple is unpacked into k and v automatically:
for k,v in d.items():
print(k, 'corresponds to', v)
Using k and v as variable names when looping over a dict is quite common if the body of the loop is only a few lines. For more complicated loops it may be a good idea to use more descriptive names:
for letter, number in d.items():
print(letter, 'corresponds to', number)
It's a good idea to get into the habit of using format strings:
for letter, number in d.items():
print('{0} corresponds to {1}'.format(letter, number))
key is simply a variable.
For Python2.X:
>>> d = {'x': 1, 'y': 2, 'z': 3}
>>> for my_var in d:
>>> print my_var, 'corresponds to', d[my_var]
x corresponds to 1
y corresponds to 2
z corresponds to 3
... or better,
d = {'x': 1, 'y': 2, 'z': 3}
for the_key, the_value in d.iteritems():
print the_key, 'corresponds to', the_value
For Python3.X:
d = {'x': 1, 'y': 2, 'z': 3}
for the_key, the_value in d.items():
print(the_key, 'corresponds to', the_value)
When you iterate through dictionaries using the for .. in ..-syntax, it always iterates over the keys (the values are accessible using dictionary[key]).
To iterate over key-value pairs, use the following:
for k,v in dict.iteritems() in Python 2
for k,v in dict.items() in Python 3
This is a very common looping idiom. in is an operator. For when to use for key in dict and when it must be for key in dict.keys() see David Goodger's Idiomatic Python article (archived copy).
I have a use case where I have to iterate through the dict to get the key, value pair, also the index indicating where I am. This is how I do it:
d = {'x': 1, 'y': 2, 'z': 3}
for i, (key, value) in enumerate(d.items()):
print(i, key, value)
Note that the parentheses around the key, value are important, without them, you'd get an ValueError "not enough values to unpack".
Iterating over dictionaries using 'for' loops
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
...
How does Python recognize that it needs only to read the key from the
dictionary? Is key a special word in Python? Or is it simply a
variable?
It's not just for loops. The important word here is "iterating".
A dictionary is a mapping of keys to values:
d = {'x': 1, 'y': 2, 'z': 3}
Any time we iterate over it, we iterate over the keys. The variable name key is only intended to be descriptive - and it is quite apt for the purpose.
This happens in a list comprehension:
>>> [k for k in d]
['x', 'y', 'z']
It happens when we pass the dictionary to list (or any other collection type object):
>>> list(d)
['x', 'y', 'z']
The way Python iterates is, in a context where it needs to, it calls the __iter__ method of the object (in this case the dictionary) which returns an iterator (in this case, a keyiterator object):
>>> d.__iter__()
<dict_keyiterator object at 0x7fb1747bee08>
We shouldn't use these special methods ourselves, instead, use the respective builtin function to call it, iter:
>>> key_iterator = iter(d)
>>> key_iterator
<dict_keyiterator object at 0x7fb172fa9188>
Iterators have a __next__ method - but we call it with the builtin function, next:
>>> next(key_iterator)
'x'
>>> next(key_iterator)
'y'
>>> next(key_iterator)
'z'
>>> next(key_iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
When an iterator is exhausted, it raises StopIteration. This is how Python knows to exit a for loop, or a list comprehension, or a generator expression, or any other iterative context. Once an iterator raises StopIteration it will always raise it - if you want to iterate again, you need a new one.
>>> list(key_iterator)
[]
>>> new_key_iterator = iter(d)
>>> list(new_key_iterator)
['x', 'y', 'z']
Returning to dicts
We've seen dicts iterating in many contexts. What we've seen is that any time we iterate over a dict, we get the keys. Back to the original example:
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
If we change the variable name, we still get the keys. Let's try it:
>>> for each_key in d:
... print(each_key, '=>', d[each_key])
...
x => 1
y => 2
z => 3
If we want to iterate over the values, we need to use the .values method of dicts, or for both together, .items:
>>> list(d.values())
[1, 2, 3]
>>> list(d.items())
[('x', 1), ('y', 2), ('z', 3)]
In the example given, it would be more efficient to iterate over the items like this:
for a_key, corresponding_value in d.items():
print(a_key, corresponding_value)
But for academic purposes, the question's example is just fine.
For Iterating through dictionaries, The below code can be used.
dictionary= {1:"a", 2:"b", 3:"c"}
#To iterate over the keys
for key in dictionary.keys():
print(key)
#To Iterate over the values
for value in dictionary.values():
print(value)
#To Iterate both the keys and values
for key, value in dictionary.items():
print(key,'\t', value)
You can check the implementation of CPython's dicttype on GitHub. This is the signature of method that implements the dict iterator:
_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
PyObject **pvalue, Py_hash_t *phash)
CPython dictobject.c
To iterate over keys, it is slower but better to use my_dict.keys(). If you tried to do something like this:
for key in my_dict:
my_dict[key+"-1"] = my_dict[key]-1
it would create a runtime error because you are changing the keys while the program is running. If you are absolutely set on reducing time, use the for key in my_dict way, but you have been warned.
If you are looking for a clear and visual example:
cat = {'name': 'Snowy', 'color': 'White' ,'age': 14}
for key , value in cat.items():
print(key, ': ', value)
Result:
name: Snowy
color: White
age: 14
This will print the output in sorted order by values in ascending order.
d = {'x': 3, 'y': 1, 'z': 2}
def by_value(item):
return item[1]
for key, value in sorted(d.items(), key=by_value):
print(key, '->', value)
Output:
y -> 1
z -> 2
x -> 3
Let's get straight to the point. If the word key is just a variable, as you have mentioned then the main thing to note is that when you run a 'FOR LOOP' over a dictionary it runs through only the 'keys' and ignores the 'values'.
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print (key, 'corresponds to', d[key])
rather try this:
d = {'x': 1, 'y': 2, 'z': 3}
for i in d:
print (i, 'corresponds to', d[i])
but if you use a function like:
d = {'x': 1, 'y': 2, 'z': 3}
print(d.keys())
in the above case 'keys' is just not a variable, its a function.
A dictionary in Python is a collection of key-value pairs. Each key is connected to a value, and you can use a key to access the value associated with that key. A key's value can be a number, a string, a list, or even another dictionary. In this case, threat each "key-value pair" as a separate row in the table: d is your table with two columns. the key is the first column, key[value] is your second column. Your for loop is a standard way to iterate over a table.

How do I create a default dictionary of dictionaries

I am trying to write some code that involves creating a default dictionary of dictionaries. However, I have no idea how to initialise/create such a thing. My current attempt looks something like this:
from collections import defaultdict
inner_dict = {}
dict_of_dicts = defaultdict(inner_dict(int))
The use of this default dict of dictionaries is to for each pair of words that I produce from a file I open (e.g. [['M UH M', 'm oo m']] ), to set each segment of the first word delimited by empty space as a key in the outer dictionary, and then for each segment in the second word delimited by empty space count the frequency of that segment.
For example
[['M UH M', 'm oo m']]
(<class 'dict'>, {'M': {'m': 2}, 'UH': {'oo': 1}})
Having just run this now it doesn't seem to have output any errors, however I was just wondering if something like this will actually produce a default dictionary of dictionaries.
Apologies if this is a duplicate, however previous answers to these questions have been confusing and in a different context.
To initialise a defaultdict that creates dictionaries as its default value you would use:
d = defaultdict(dict)
For this particular problem, a collections.Counter would be more suitable
>>> from collections import defaultdict, Counter
>>> d = defaultdict(Counter)
>>> for a, b in zip(*[x.split() for x in ['M UH M', 'm oo m']]):
... d[a][b] += 1
>>> print(d)
defaultdict(collections.Counter,
{'M': Counter({'m': 2}), 'UH': Counter({'oo': 1})})
Edit
You expressed interest in a comment about the equivalent without a Counter. Here is the equivalent using a plain dict
>>> from collections import defaultdict
>>> d = defaultdict(dict)
>>> for a, b in zip(*[x.split() for x in ['M UH M', 'm oo m']]):
... d[a][b] = d[a].get(b, 0) + 1
>>> print(d)
defaultdict(dict, {'M': {'m': 2}, 'UH': {'oo': 1}})
You also could a use a normal dictionary and its setdefault method.
my_dict.setdefault(key, default) will look up my_dict[key] and ...
... if the key already exists, return its current value without modifying it, or ...
... assign the default value (my_dict[key] = default) and then return that.
So you can call my_dict.setdefault(key, {}) always when you want to get a value from your outer dictionary instead of the normal my_dict[key] to retrieve either the real value assigned with this key if it#s present, or to get a new empty dictionary as default value which gets automatically stored into your outer dictionary as well.
Example:
outer_dict = {"M": {"m": 2}}
inner_dict = d.setdefault("UH", {})
# outer_dict = {"M": {"m": 2}, "UH": {}}
# inner_dict = {}
inner_dict["oo"] = 1
# outer_dict = {"M": {"m": 2}, "UH": {"oo": 1}}
# inner_dict = {"oo": 1}
inner_dict = d.setdefault("UH", {})
# outer_dict = {"M": {"m": 2}, "UH": {"oo": 1}}
# inner_dict = {"oo": 1}
inner_dict["xy"] = 3
# outer_dict = {"M": {"m": 2}, "UH": {"oo": 1, "xy": 3}}
# inner_dict = {"oo": 1, "xy": 3}
This way you always get a valid inner_dict, either an empty default one or the one that's already present for the given key. As dictionaries are mutable data types, modifying the returned inner_dict will also modify the dictionary inside outer_dict.
The other answers propose alternative solutions or show you can make a default dictionary of dictionaries using d = defaultdict(dict)
but the question asked how to make a default dictionary of default dictionaries, my navie first attempt was this:
from collections import defaultdict
my_dict = defaultdict(defaultdict(list))
however this throw an error: *** TypeError: first argument must be callable or None
so my second attempt which works is to make a callable using the lambda key word to make an anonymous function:
from collections import defaultdict
my_dict = defaultdict(lambda: defaultdict(list))
which is more concise than the alternative method using a regular function:
from collections import defaultdict
def default_dict_maker():
return defaultdict(list)
my_dict = defaultdict(default_dict_maker)
you can check it works by assigning:
my_dict[2][3] = 5
my_dict[2][3]
>>> 5
or by trying to return a value:
my_dict[0][0]
>>> []
my_dict[5]
>>> defaultdict(<class 'list'>, {})
tl;dr
this is your oneline answer my_dict = defaultdict(lambda: defaultdict(list))

Resources