问题
While playing around with input validation, specifically checking whether the supplied data have all the required attributes specified, and discarding attributes that I don't want, I did something like this:
>>> input = {'v1': 'val1', 'a2':'val2', 'a3':'val3'}
>>> print input
{'v1': 'val1', 'a3': 'val3', 'a2': 'val2'}
>>> goodkeys = ['a2', 'a3']
>>> print goodkeys
['a2', 'a3']
>>> output = {}
>>> for a in goodkeys:
... output[a] = input[a]
...
>>>
>>> print output
{'a3': 'val3', 'a2': 'val2'}
Which of course works. But it occurred to me that it may be possible to do this in a more pythonic way. I tried:
>>> output = {}
>>> print output
{}
>>> output = { a:v for a in goodkeys for v in input[a] }
>>> print output
{'a3': '3', 'a2': '2'}
>>>
Which for half a second I thought worked, then I realized that the values are wrong. Is there a pretty Python method? And what happened, where did Python get those values?
回答1:
You could use dictionary view objects:
goodkeys = {'a2', 'a3'}
output = {a: input[a] for a in input.viewkeys() & goodkeys}
where goodkeys
is a set; dict.viewkeys() produces a set-like object that reflects the contents of the dictionary, and & goodkeys
produces the intersection between those keys and the goodkeys
set. That way you only ever produce keys that are both in the input dictionary and the set of good keys.
You created a nested loop like this:
for a in goodkeys:
for v in input[a]:
# v is a single character in the string value
Demo:
>>> input = {'v1': 'val1', 'a2':'val2', 'a3':'val3'}
>>> goodkeys = {'a2', 'a3'}
>>> {a: input[a] for a in input.viewkeys() & goodkeys}
{'a3': 'val3', 'a2': 'val2'}
Since input[a]
is a string, your inner loop produced the individual characters of each value:
>>> for a in goodkeys:
... for v in input[a]:
... print a, v
...
a3 v
a3 a
a3 l
a3 3
a2 v
a2 a
a2 l
a2 2
Keys must be unique, so for a2
, one of v
, a
, l
and 2
is picked with the others discarded. The dictionary comprehension sets 'a2': 'v'
first, then 'a2': 'a'
, etc. and only 'a2': '2'
remains in the output, in the end.
You didn't need to use that inner loop; you could have stuck with:
{a: input[v] for a in goodkeys}
except that if there are any keys in goodkeys
that are not in input
you'd get a KeyError
. The dictionary view approach neatly sidesteps that issue.
回答2:
output = { a:input[a] for a in goodkeys }
Your second for
iterates through the characters of the string values.
回答3:
You may be over thinking this. Just try changing
output = { a:v for a in goodkeys for v in input[a] }
to simply...
output = { a:input[a] for a in goodkeys }
来源:https://stackoverflow.com/questions/27447684/python-dictionary-comprehension-to-copy-some-pairs-to-a-new-dictionary