Dynamic dictionary in Python - python

Python v3.4.2
I've created a dictionary from a list of keys and stored the number of times the key occurs.
My code works as intended, but I'm unsure WHY it works:
count_dict = {key: key_list.count(key) for key in key_list}
I see that for every key in key_list, I'm adding 'key' and 'count' value pairs to the dictionary. But why does this syntax work? I would expect to need to declare an empty dictionary and then add the key value pairs within a for..in.. loop.
It appears to work for lists as well. But when I try something such as:
print(x) for x in key_list
I get a syntax error.

this is known as a dictionary comprehension
it was introduced in python 2.7
see: https://docs.python.org/2/tutorial/datastructures.html#dictionaries
there are also set comprehensions, list comprehensions, generator statements...
however you are right you cannot just write arbitrary code and expect it to work
ie print(x) for x in key_list is indeed a syntax error

Related

Logic behind accessing dictionary values in python

Rookie here and I couldn't find a proper explanation for this.
We have a simple dict:
a_dict = {'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}
to loop through and access the values of this dict I have to call
for key in a_dict:
print(key, '->', a_dict[key])
I am saying about
a_dict[key]
specifically. Why python use this convention? Where is a logic behind this? When I want to get values of a dictionary I should call it something like
a_dict[value] or a_dict[values] etc
instead (thinking logically).
Could anyone explain it to make more sense please?
edit:
to be clear: why python use a_dict[key] to access dict VALUE instead of a_dict[value]. LOGICALLY.
according to your question, I think you meant why python does not use index instead of key to reach values in the dict.
Please take note that there are 4 main data container in python, and each for its usage. (there are also other containers like counter and ...)
for example elements of list and tuple is reachable by their indices.
a = [1,2,3,4,5]
print(a[0]) would print 1
but dictionary as its name shows, maps from some objects (keys in python terminology) to some other objects(values in python terminology). so we would call the key instead of index and the output would be the value.
a = { 'a':1 , 'b':2 }
print(a['a']) would print 1
I hope it makes it a bit more clear for you.
I think you are misunderstanding some terminology around dictionaries:
In your example, your keys are color, fruit, and pet.
Your values are blue, apple, and dog.
In python, you access your values by calling a_dict[key], for example a_dict["color"] will return "blue".
If python instead used your suggested method of a_dict[value], you would have to know what your value was before trying to access it, e.g. a_dict["blue"] would be needed to get "blue", which makes very little sense.
As in Feras's answer, try reading up more on how dictionaries work here
Its because, a dictionary in python, maps the keys and values with a hash function internally in the memory.
Thus, to get the value, you've to pass in the key.
You can sort of think it like indices of the list vs the elements of the list, now to extract a particular element, you would use lst[index]; this is the same way dictionaries work; instead of passing in index you would've to pass in
the key you used in the dictionary, like dict[key].
One more comparison is the dictionary (the one with words and meanings), in that the meanings are mapped to the words, now you would of course search for the word and not the meaning given to the word, directly.
You are searching for a value wich you don't know if it exists or not in the dict, so the a_dict[key] is logic and correct

Unpacking a list of dictionaries to get all their keys

I am writing a script to add missing keys within a list of dictionaries and assign them a default value. I start by building a set of all the possible keys that appear in one or more dictionaries.
I adapted a nice snippet of code for this but I'm having trouble fully wrapping my head around how it works:
all_keys = set().union(*dicts)
From how I understand this, my list of dictionaries dicts is unpacked into individual (dictionary) arguments for the union method, which merges them all together with the empty set, giving me a set of keys.
What isn't clear to me is why this code builds the set using just the keys of the dictionaries, while discarding their associated values. This is in fact what I want to happen, but how it is achieved here is murky. For example, I know unpacking a dictionary with a single * unpacks just the keys, which seems like what is happening here, except in my code I am not explicitly unpacking the contents of the dictionaries, only the list that contains them.
Can someone explain to me a little more explicitly what is happening under the hood here?
If you wrote:
s1 = set()
s2 = s1.union(iterable1, iterable2, iterable3)
the union() method would unpack each iterableX to get the values to combine with s1.
Your code is simply getting all the iterables by spreading dicts, so it's equivalent to
s2 = s1.union(dicts[0], dicts[1], dicts[2], ...)
and it unpacks each dictionary, getting their keys.

Basic Dictionay (key maps the value)

What is the back-end of this situation, where two same keys have different values but the output is little strange? What's going on?
Dictionaries are indexed by Keys. If you store using a key that is already in use, the old value associated with that key is forgotten. It is an error to extract a value using a non-existent key.
Read more about dictionaries in https://docs.python.org/2/tutorial/datastructures.html#dictionaries before using them
an one-line excerpt from python documentation:
If you store using a key that is already in use, the old value
associated with that key is forgotten.
I guess it's easier for you to understand it with some codes here.
d = {'a':'A', 'b':'B', 'a':'C'}
d['a']
# output
'C'
print(d)
# output
{'b':'B', 'a':'C'}
it's not very hard to see that python has deleted the old key value pair for a here and the dictionary itself has only 2 items in it. this is basically what python meant by forgotten.

Python sorting deep in a datastructure

I'm in pretty far over my head right now for Python scripting and don't really understand what I'm doing.
I have a dictionary where the keys are strings and the values are lists of strings. I need to sort the strings within the list alphanumerically such that
"role_powerdns": [
"name-2.example.com",
"name-1.example.com",
"name-3.example.com"
],
Looks like this
"role_powerdns": [
"name-1.example.com",
"name-2.example.com",
"name-3.example.com"
],
The full original code I'm working off of is here for reference. https://github.com/AutomationWithAnsible/ansible-dynamic-inventory-chef/blob/master/chef_inventory.py
I don't fully understand myself how the code I'm working off of works, I just know the data structure it's returning.
My local additions to that base code is filtering out IPs and inserting .sub into the strings. I've tried reusing the comprehension syntax I've got below for modifying the strings to sort the strings. Could someone show provide an example of how to iterate through a nested structure like this? Alternatively if doing this sort of sorting so late in the script is not appropriate, when generally should it be handled?
def filterIP(fullList):
regexIP = re.compile(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$')
return filter(lambda i: not regexIP.search(i), fullList)
groups = {key : [domain.replace('sub.example.com', 'example.com') for domain in filterIP(list(set(items)))] for (key, items) in groups.iteritems() }
print(self.json_format_dict(groups, pretty=True))
If d is your dictionary, you can sort all its values by
for _, l in d.items():
l.sort()
fuglede's answer almost worked for me. What I needed to do instead was use iteritems. items was doing some funky local version that was being thrown away after the code block was done with it per this
Iterating over dictionaries using 'for' loops
for key, value in groups.iteritems():
value.sort()

Enigmatic Naming of Lists in Python

I am writing a program in python and I am using a dictionary. I need to create an empty list for each key in the dictionary, and each list needs to have the same name as the key. The keys are user entered, which is why I can't just make a list in the conventional way.
This was the first thing I tried
a = {"x":1, "y":2, "z"3}
list(a.keys())
a.pop() = [] # This raises an error
I also tried to make the lists when the dictionary was being created, but this did not work either:
a = {}
b = input("INPUT1")
c = input("INPUT2")
a[b] = c
b = []
This created a list with the name "b" rather than whatever the user entered. Please help!!
This really doesn't make much sense. Why do your lists need 'names'? For that matter, what do you mean by 'names'?
Secondly, your code doesn't do anything. a.keys() is already a list. Calling list on it doesn't do anything else. But in any case, whatever the result of that line is, it is immediately thrown away, as you don't store the result anywhere.
pop doesn't work on dictionaries, it works on lists. And what does it mean to set the result of pop to a list? Are you trying to dynamically create a set of local variables with the names of each key in the dictionary? If so, why? Why not simply create another dictionary with the keys of the first, and each value as a new list? That can be done in one command:
b = dict((k, []) for k in b.keys())
(Note that dict.fromkeys() won't work here, as that would cause each element to share the same list.)
Use raw_input instead. input expects a valid Python expression and WILL evaluate whatever the user inputs. So if the user inputs a word, it'll evaluate that word and try to find an object with its name.
EDIT: for further clarification, input("INPUT1") is the equivalent of doing eval(raw_input("INPUT1")), for instance.

Categories