let's make first the code clearer:
dict( # constructor
(i.tag, # key
(type(i.text) == str and i.text.strip() or i.text) # value
)
for i in r # driver of the generator
if i.tag != "tid_item" # conditional selector
)
What you have here, is not yet a dictionary, but a constructor of a dictionary, using a generator. After this is run, the variable item it is assigned to will contain a dictionary
the for loop inside this constructor is the generator to create all the elements: it loops over all elements in r, if it satisfies the condition, then it will create a tuple ( key, value) -> creating a 'on-the-fly' list of elements.
The boolean selector for the 'value' is also simple if we write it differently:
value = i.text.strip() if (type(i.text) == str) else i.text
Answer from Jeroen Decroos on Stack Overflowlet's make first the code clearer:
dict( # constructor
(i.tag, # key
(type(i.text) == str and i.text.strip() or i.text) # value
)
for i in r # driver of the generator
if i.tag != "tid_item" # conditional selector
)
What you have here, is not yet a dictionary, but a constructor of a dictionary, using a generator. After this is run, the variable item it is assigned to will contain a dictionary
the for loop inside this constructor is the generator to create all the elements: it loops over all elements in r, if it satisfies the condition, then it will create a tuple ( key, value) -> creating a 'on-the-fly' list of elements.
The boolean selector for the 'value' is also simple if we write it differently:
value = i.text.strip() if (type(i.text) == str) else i.text
Firstly, lets decompose your example:
item_init = ((i.tag, (type(i.text) == str and i.text.strip() or i.text)) for i in r if i.tag != "tid_item")
item = dict(item_init)
Now, if you look at the definition of the type dict in python (help(dict)), you will see that a dict object can be initialized with an iterable of (key, value) pairs. The item_init variable contains a generator and yield an iterable of tuples.
Next, look at the expression (i.tag, (type(i.text) == str and i.text.strip() or i.text)). You may not understand the second part of the expression because it looks like a boolean operation but is actually a conditionnal assignment operation which means:
if
type(i.text)isstrthen assigni.text.strip()else, assigni.text
Finally, the item_init object is a generator of 2-uples where, for each element of r, the first part is the tag and the second is the text (stripped, if necessary). The tag will be used as keys and the text as values in the final dict object.
Videos
key is just a variable name.
Copyfor 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:
Copyfor key, value in d.items():
For Python 2.x:
Copyfor 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
Copyfor k in dict: ...which is equivalent to, but much faster than
Copyfor 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:
Copyfor key in dict.iterkeys(): ... for value in dict.itervalues(): ... for key, value in dict.iteritems(): ...This means that
for x in dictis shorthand forfor 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.