I have to create more than 10 dictionaries. Is there a more efficient way to create multiple dictionaries using Python's built-in libraries as described below:
dict1_1= {
"value":100,
"secondvalue":200,
"thirdvalue":300
}
dict1_2= {
"fixedvalue":290,
"changedvalue":180,
"novalue":0
}
The dict builtin will create a dictionary from keyword arguments:
>>> dict(a=1, b=2)
{'a': 1, 'b': 2}
but you can use integers as keyword arguments:
>>> dict(a=1, 2=2)
File "<stdin>", line 1
dict(a=1, 2=2)
^^
SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
However, dict will also accept an iterable of key/value tuples, and in this case they keys may be integers
>>> dict([('a', 1), (2, 2)])
{'a': 1, 2: 2}
If your keys are the same for all dicts you can use zip:
>>> keys = ('a', 2)
>>> values = [(1, 2), (3, 4)]
>>> for vs in values:
... print(dict(zip(keys, vs)))
...
{'a': 1, 2: 2}
{'a': 3, 2: 4}
However, if your keys are not consistent, there's nothing wrong with using the literal {...} constructor. In fact, if it's efficiency that you want, the literal constructor may be the best choice.
you can use a simple function to create new dictionaries. Look at the code below:
func = lambda **kwargs: kwargs
my_dict = func(x="test", y=1, z=[1, 'test'])
Note that the keys of dictionary can only be string
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.
Hi i am making this class
class multiset(dict):
def __new__(cls,iterabile):
d = dict()
for i in iterabile:
if i not in d.keys():
d[i] = iterabile.count(i)
return super().__new__(cls,d)
This class is a custom dict that, from an input list, it create a dict where the keys are the element and the values are the number of occurences of the keys element in the list.
The problem is that the super().__new__(cls,d) return this error:
Traceback (most recent call last):
File "", line 1, in
m = multiset([1,1,1,2,1,3,2,3])
TypeError: cannot convert dictionary update sequence element #0 to a sequence
Change to using __init__() and don't create an explicit new dict because self is already a dict because multiset inherits from dict:
class multiset(dict):
def __init__(self,iterable):
for i in iterable:
if i not in self.keys():
self[i] = iterable.count(i)
m = multiset([1,1,1,2,1,3,2,3])
print( m )
# prints: {1: 4, 2: 2, 3: 2}
But as ndclt points out, collections.Counter already does this.
Coming from the Python documentation:
The dict() constructor builds dictionaries directly from sequences of key-value pairs:
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}
And you're giving the dict constructor super().__new__(cls,d) which call the dict.__init__ a dict instead of a key-value pairs.
Why don't use a Counter which looks like to do what you want and behave like a dictionary:
>>> from collections import Counter
>>> Counter([1,1,1,2,1,3,2,3])
Counter({1: 4, 2: 2, 3: 2})
>>> Counter([1,1,1,2,1,3,2,3])[1]
4
In python 2 I used:
d = {'a': 1, 'b': 2, 'c': 3}
for k in d.keys():
d[k] = d[k] * 2
print(d)
# {'a': 2, 'b': 4, 'c': 6}
In python 3 I use:
d = {'a': 1, 'b': 2, 'c': 3}
for k in d:
d[k] = d[k] * 2
print(d)
# {'a': 2, 'b': 4, 'c': 6}
This new syntax gives me the feeling I'm iterating over something (the dict) and modifying it, which is bad. But in truth I'm only iterating over the keys, so this should not bring any trouble, right?
Iterating over a dictionary and modifying values is perfectly fine. Each time you call dict.__getitem__ / dict.__setitem__, or respectively its syntactic sugar dict[] / dict[] = ..., the value for a key is retrieved. You can overwrite values for keys as you iterate items, as changing values does not change key hashes and therefore does not impact the iterator.
What's not fine is adding or removing keys as you iterate over a view of a dictionary. The reason why this is problematic is given in the docs:
The objects returned by dict.keys(), dict.values() and dict.items()
are view objects. They provide a dynamic view on the dictionary’s
entries, which means that when the dictionary changes, the view
reflects these changes.
I don't see a reason why it should be bad practice if you do not change the set of keys of the dictionary. Your examples do not do that, so they are just fine.
The things starts getting messy if your changing involves adding or removing elements:
d = {}
k = d.keys()
i = iter(k)
d[42] = 23
next(i)
This will raise an exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
And your example can probably be improved a little by iterating over the items instead of the keys alone:
d = dict(a=1, b=2, c=3)
for k, v in d.items():
d[k] = v * 2
or in the special case of your "just doubling":
for k in d.keys():
d[k] *= 2
But I guess your real use case is probably more complex.
EDIT: Be aware that if you are still using Python2, you should use .iteritems() and .iterkeys() instead of .items() and .keys().