Python dictionary assignment missing - python

Python stores key/values in dictionaries.
In this example values (which are dictionaries themselves) are stored in "lut".
lut = {}
pair=" "
line = "halhak"
for letter in line.strip() + ' ':
d = lut.setdefault(pair, {})
d[letter] = d.get(letter, 0) + 1
pair = pair[1] + letter
The key / values are:
for key in lut:
print key, "/", lut[key]
/ {'h': 1}
ak / {' ': 1}
al / {'h': 1}
lh / {'a': 1}
ha / {'k': 1, 'l': 1}
h / {'a': 1}
My question:
I don't see where the loop assigns any values to "lut" different from "{}".

d is always a reference to some element of lut. Here's a similar example that shows how it works.
>>> lut = {1 : {}}
>>> d = lut[1]
>>> d is lut[1]
True
lut[1] is a reference to some dictionary, and the value of d is a reference to that same dictionary, as verified by the is operator. Operations on d and operations on lut[1] operate on the same object.
In your actual code, a call to setdefault is involved:
d = lut.setdefault(pair, {})
The setdefault method does two things: if pair is not in lut, it first sets the value of lut[pair] to the given value. Then it returns the value of lut[pair]. It's identical to the following code
if pair not in lut:
lut[pair] = {}
d = lut[pair]

Only empty dicts {} are directly added to lut, using setdefault().
As described in the documentation, setdefault always returns a value for any given key:
setdefault(key[, default])
If key is in the dictionary, return its value.
If not, insert key with a value of default and return default. default defaults to None.
So d is always a dict - one of the values in the outer lut dict.
However, the next line modifies one of these (initially empty) dicts out of lut,
which is why you see populated dicts in the results.

The expression d = lut.setdefault(pair, {}) does one of two things, depending on wether or not the pair key is present:
pair is present; return a reference to the value
pair is not present; set lut[pair] to the second argument ({}), and return it.
Either way, you now have a reference to the object referenced by lut[pair], which is always a dictionary.
Modifying that dictionary means that all references everywhere can see those changes. d[letter] = d.get(letter, 0) + 1 will set a key-value pair in that dictionary. Since both d and lut[pair] reference that dictionary, you can later iterate over lut to see those changes.
A quick demo:
>>> lut = {}
>>> d = lut.setdefault('foo', {})
>>> lut
{'foo': {}}
>>> d
{}
>>> d is lut['foo']
True
>>> d['bar'] = 42
>>> d
{'bar': 42}
>>> lut
{'foo': {'bar': 42}}
>>> lut['foo']
{'bar': 42}

Related

python 3 dictionary key to a string and value to another string

if there is a dictionary:
dict={'a':'b'}
in python 3, i would like to convert this dictionary key to a string and its value to another string:
print(key)
key='a'
print(type(key))
str
print(value)
value='a'
print(type(value))
str
Some attempts:
str(dict.key()) # returns 'dict' object has no attribute 'key'
json.dump(dict) # returns {'a':'b'} in string, but hard to process
Any easy solution? Thank you!
Use dict.items():
You can use dict.items() (dict.iteritems() for python 2), it returns pairs of keys and values, and you can simply pick its first.
>>> d = { 'a': 'b' }
>>> key, value = list(d.items())[0]
>>> key
'a'
>>> value
'b'
I converted d.items() to a list, and picked its 0 index, you can also convert it into an iterator, and pick its first using next:
>>> key, value = next(iter(d.items()))
>>> key
'a'
>>> value
'b'
Use dict.keys() and dict.values():
You can also use dict.keys() to retrieve all of the dictionary keys, and pick its first key. And use dict.values() to retrieve all of the dictionary values:
>>> key = list(d.keys())[0]
>>> key
'a'
>>> value = list(d.values())[0]
>>> value
'b'
Here, you can use next(iter(...)) too:
>>> key = next(iter(d.keys()))
>>> key
'a'
>>> value = next(iter(d.values()))
'b'
Ensure getting a str:
The above methods don't ensure retrieving a string, they'll return whatever is the actual type of the key, and value. You can explicitly convert them to str:
>>> d = {'some_key': 1}
>>> key, value = next((str(k), str(v)) for k, v in d.items())
>>> key
'some_key'
>>> value
'1'
>>> type(key)
<class 'str'>
>>> type(value)
<class 'str'>
Now, both key, and value are str. Although actual value in dict was an int.
Disclaimer: These methods will pick first key, value pair of dictionary if it has multiple key value pairs, and simply ignore others. And it will NOT work if the dictionary is empty. If you need a solution which simply fails if there are multiple values in the dictionary, #SylvainLeroux's answer is the one you should look for.
To have a solution with several keys in dict without any import I used the following light solution.
dict={'a':'b','c':'d'}
keys = "".join(list(dict.keys()))
values = "".join(list(dict.values()))
>>> d = { 'a': 'b' }
>>> d.items()
dict_items([('a', 'b')])
At this point, you can use a destructuring assignement to get your values:
>>> [[key, value]] = d.items()
>>> key
'a'
>>> value
'b'
One advantage in this solution is it will fail in case of d containing several entries, instead of silently ignoring the issue.
>>> d = { 'a': 'b', 'c':'d' }
>>> [[key, value]] = d.items()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 1)
Finally, if you need to ensure key and value to be strings, you may add a list comprehension:
>>> d = { 1: 2 }
>>> [[key, value]] = ((str(key), str(value)) for key,value in d.items())
>>> key
'1'
>>> value
'2'
Make lists of keys and values:
dict={'a':'b'}
keys = list(dict.keys())
values = list(dict.values())
then make variables:
key = keys[0]
value = values[0]
https://docs.python.org/3/library/stdtypes.html#typesmapping
The methods are you looking for are keys() and values().

Python 3 dictionary d.items(), d.keys()

I'm kind of confused on d.items() and d.keys(). My textbook said that they return view objects that are tuples but they can be changed? For instance, my code is this
d = {"Bob":27, "Frank":75}
for key, value in d.items():
if d[key] == 27:
d[key] = 20
print(d)
It prints out 20 instead of 27.
What your textbook means is that if the keys of the dictionary change, then so will the view.
d = {1: 1}
keys = d.keys() # dict_keys([1])
d[2] = 2
keys # dict_keys([1, 2])
The same happens for items.
d = {1: 1}
items = d.items() # dict_items([(1, 1)])
d[2] = 2
keys # dict_keys([(1, 1), (2, 2)])
Also, they are not tuples, they have their own class.
isinstance(d.keys(), tuple) # False
type(d.keys()) # <class 'dict_keys'>
type(d.items()) # <class 'dict_items'>
a = {
'a': 'aa',
'b': 'bb',
'c': 'cc'
}
for k,v in a.items(): # does't change anything.
k = 'c' # k is the first item of the tuples in the dict_items object
for k in a.keys(): # doesn't change anything.
k = 'd' # k is the first item of the tuples in the dict_keys object
for k,v in a.items():
# you are using __setitem__ method of the dictionary with the first item of the tuple
# so you are not actually changing the tuple
# you are just using the tuple to index the dictionary
a[k] = v + '!!!' # you find the value of the given key, and added a string to it
print(a.items()) # will print a dict_items object containing key,value tuples of the dictionary
-~-~-~-~-~-
for a in a.items(): # does't change anything
print(isinstance(a,tuple))
The above code vill give you all True because every item in the dict_items object is indeed a tuple. a.items() doesn't return tuples yet returns an object which holds tuples.

Python update a key in dict if it doesn't exist

I want to insert a key-value pair into dict if key not in dict.keys().
Basically I could do it with:
if key not in d.keys():
d[key] = value
But is there a better way? Or what's the pythonic solution to this problem?
You do not need to call d.keys(), so
if key not in d:
d[key] = value
is enough. There is no clearer, more readable method.
You could update again with dict.get(), which would return an existing value if the key is already present:
d[key] = d.get(key, value)
but I strongly recommend against this; this is code golfing, hindering maintenance and readability.
Use dict.setdefault():
>>> d = {'key1': 'one'}
>>> d.setdefault('key1', 'some-unused-value')
'one'
>>> d # d has not changed because the key already existed
{'key1': 'one'}
>>> d.setdefault('key2', 'two')
'two'
>>> d
{'key1': 'one', 'key2': 'two'}
Since Python 3.9 you can use the merge operator | to merge two dictionaries. The dict on the right takes precedence:
new_dict = old_dict | { key: val }
For example:
new_dict = { 'a': 1, 'b': 2 } | { 'b': 42 }
print(new_dict) # {'a': 1, 'b': 42}
Note: this creates a new dictionary with the updated values.
With the following you can insert multiple values and also have default values but you're creating a new dictionary.
d = {**{ key: value }, **default_values}
I've tested it with the most voted answer and on average this is faster as it can be seen in the following example, .
Speed test comparing a for loop based method with a dict comprehension with unpack operator method.
if no copy (d = default_vals.copy()) is made on the first case then the most voted answer would be faster once we reach orders of magnitude of 10**5 and greater. Memory footprint of both methods are the same.
You can also use this solution in only one line of code:
dict[dict_key] = dict.get(dict_key,value)
The second argument of dict.get is the value you want to assign to the key in case the key does not exist. Since this evaluates before the assignment to dict[dict_key] = , we can be sure that they key will exist when we try to access it.

Python dictionary view

Is a dictionary the right type for data where I want to look up entries based on an index, e.g.
dictlist = {}
dictlist['itemid' + '1'] = {'name':'AAA', 'class':'Class1', 'nonstandard':'whatever'}
dictlist['itemid' + '2'] = {'name':'BBB', 'class':'Class2', 'maynotbehere':'optional'}
dictlist['itemid' + '3'] = {'name':'CCC', 'class':'Class3', 'regular':'or not'}
I can now address a specific item, e.g.
finditem='itemid2'
dictitem = {}
try:
dictitem[finditem] = dictlist[finditem]
print dictitem
except KeyError:
print "Nothing there"
Is that the right way to create such a lookup table in python?
If I now wanted to print the data, but only the Item ID, and an associated dictionary with only name and class "properties", how can I do that?
I am looking for something that will create a new dictionary by copying the desired properties only, or else present a limited view of the existing dictionary, as if the unspecified properties were not there. So for example
view(dictlist, 'name', 'class')
will return a dictionary that displays a restricted view of the list, showing only the name and class keys. I have tried
view = {}
for item in dictlist:
view[item] = {dictlist[item]['name'], dictlist[item]['class']}
print view
Which returns
{'itemid1': set(['AAA', 'Class1']), 'itemid3': set(['Class3', 'CCC']), 'itemid2': set(['Class2', 'BBB'])}
Instead of
{'itemid1': {'name':'AAA', 'class':'Class1'}, 'itemid3': {'name':'CCC', 'class':'Class3'}, 'itemid2': {'name':'BBB', 'class':'Class2'} }
Note that {'foo', 'bar'} is a set literal, not a dictionary literal, as it does not have the key: value syntax required for a dictionary:
>>> type({'foo', 'bar'})
<class 'set'>
>>> type({'foo': 'bar'})
<class 'dict'>
You need to be more careful with your syntax generally; I have no idea what the random closing square brackets ] are doing in the output you claim you want, and it's missing a closing brace }.
You could extend your current code to do keys and values as follows:
for item in dictlist:
view[item] = {'name': dictlist[item]['name'],
'class': dictlist[item]['class']}
but a more generic function would look like:
def view(dictlist, *keys):
output = {}
for item in dictlist:
output[item] = {}
for key in keys:
output[item][key] = dictlist[item].get(key)
return output
note the use of dict.get to handle missing keys gracefully:
>>> d = {'foo': 'bar'}
>>> d.get('foo')
'bar' # returns the value if key present, or
>>> d.get('baz')
>>> # returns None by default
or, using a "dictionary comprehension":
def view(dictlist, *keys):
return {k1: {k2: v2 for k2, v2 in v1.items() if k2 in keys}
for k1, v1 in dictlist.items()}
(This will exclude missing keys from the output, whereas the previous code will include them with None value - which is preferable will depend on your use case.)
Note the use of *keys to take an arbitrary number of positional arguments:
>>> def test(d, *keys):
print(keys)
>>> test({}, "foo", "bar", "baz")
('foo', 'bar', 'baz')

Remove an item from a dictionary when its key is unknown

What is the best way to remove an item from a dictionary by value, i.e. when the item's key is unknown? Here's a simple approach:
for key, item in some_dict.items():
if item is item_to_remove:
del some_dict[key]
Are there better ways? Is there anything wrong with mutating (deleting items) from the dictionary while iterating it?
The dict.pop(key[, default]) method allows you to remove items when you know the key. It returns the value at the key if it removes the item otherwise it returns what is passed as default. See the docs.'
Example:
>>> dic = {'a':1, 'b':2}
>>> dic
{'a': 1, 'b': 2}
>>> dic.pop('c', 0)
0
>>> dic.pop('a', 0)
1
>>> dic
{'b': 2}
Be aware that you're currently testing for object identity (is only returns True if both operands are represented by the same object in memory - this is not always the case with two object that compare equal with ==). If you are doing this on purpose, then you could rewrite your code as
some_dict = {key: value for key, value in some_dict.items()
if value is not value_to_remove}
But this may not do what you want:
>>> some_dict = {1: "Hello", 2: "Goodbye", 3: "You say yes", 4: "I say no"}
>>> value_to_remove = "You say yes"
>>> some_dict = {key: value for key, value in some_dict.items() if value is not value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 3: 'You say yes', 4: 'I say no'}
>>> some_dict = {key: value for key, value in some_dict.items() if value != value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 4: 'I say no'}
So you probably want != instead of is not.
a = {'name': 'your_name','class': 4}
if 'name' in a: del a['name']
A simple comparison between del and pop():
import timeit
code = """
results = {'A': 1, 'B': 2, 'C': 3}
del results['A']
del results['B']
"""
print timeit.timeit(code, number=100000)
code = """
results = {'A': 1, 'B': 2, 'C': 3}
results.pop('A')
results.pop('B')
"""
print timeit.timeit(code, number=100000)
result:
0.0329667857143
0.0451040902256
So, del is faster than pop().
I'd build a list of keys that need removing, then remove them. It's simple, efficient and avoids any problem about simultaneously iterating over and mutating the dict.
keys_to_remove = [key for key, value in some_dict.iteritems()
if value == value_to_remove]
for key in keys_to_remove:
del some_dict[key]
items() returns a list, and it is that list you are iterating, so mutating the dict in the loop doesn't matter here. If you were using iteritems() instead, mutating the dict in the loop would be problematic, and likewise for viewitems() in Python 2.7.
I can't think of a better way to remove items from a dict by value.
c is the new dictionary, and a is your original dictionary, {'z','w'}
are the keys you want to remove from a
c = {key:a[key] for key in a.keys() - {'z', 'w'}}
Also check: https://www.safaribooksonline.com/library/view/python-cookbook-3rd/9781449357337/ch01.html
y={'username':'admin','machine':['a','b','c']}
if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')]
There is nothing wrong with deleting items from the dictionary while iterating, as you've proposed. Be careful about multiple threads using the same dictionary at the same time, which may result in a KeyError or other problems.
Of course, see the docs at http://docs.python.org/library/stdtypes.html#typesmapping
This is how I would do it.
for key in some_dict.keys():
if some_dict[key] == item_to_remove:
some_dict.pop(key)
break

Categories

Resources