Take the great code from @karlknechtel and see what it does:
>>> d = dict((m.get(k, k), v) for (k, v) in d.items()) {'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
But how does it work?
To create a dictionary, you can use the dict() function. He is expecting a list of tuples. In 3.x and> 2.7 you can also use dictionary comprehension (see Answer by @nightcracker).
Let me parse the dict argument. First we need a list of all the elements in m. Each element is a tuple in the format (key, value).
>>> d.items() [('group_id', 3), ('user_id', 1), ('user', 'user1'), ('group_name', 'ordinary users')]
Given the key value k , we can get the correct key value from m by executing m[k] .
>>> k = 'user_id' >>> m[k] 'uid'
Unfortunately, not all keys in d also exist in m .
>>> k = 'user' >>> m[k] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'user'
To get around this, you can use d.get(x, y) , which returns d[x] if the key x exists, or the default value y if it is not. Now, if the key k from d does not exist in m , we just save it, so by default it is k .
>>> m.get(k, k). 'user'
Now we are ready to build a list of tuples for the delivery of dict() . To create a list on one line, we can use list comprehension .
To create a list of squares, you must write the following:
>>> [x**2 for x in range(5)] [0, 1, 4, 9, 16]
In our case, it looks like this:
>>> [(m.get(k, k), v) for (k, v) in d.items()] [('gid', 3), ('uid', 1), ('user', 'user1'), ('group', 'ordinary users')]
This is a sip, let's look at it again.
Give me a list [...] which consists of sets:
[(.., ..) ...]
I want one tuple for each element x in d :
[(.., ..) for x in d.items()]
We know that each element is a tuple with two components, so we can decompose it into two variables k and v .
[(.., ..) for (k, v) in d.items()]
Each tuple must have a right key from m as the first component, or k if k does not exist in m and the value is from d.
[(m.get(k, k), v) for (k, v) in d.items()]
We can pass it as an argument to dict() .
>>> dict([(m.get(k, k), v) for (k, v) in d.items()]) {'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
Looks nice! But wait, you can say @karlknechtel did not use square brackets.
That's right, he did not use list comprehension, but expressed a generator. Simply put, the difference is that comprehension of the list creates the entire list in memory, while the expression of the generator is evaluated by element at a time. If the list acts as an intermediate result, it is usually useful to use a generator expression. In this example, it doesn't really matter, but it's a good habit to get used to.
Equivalent expressions of generators are as follows:
>>> ((m.get(k, k), v) for (k, v) in d.items()) <generator object <genexpr> at 0x1004b61e0>
If you pass a generator expression as an argument to a function, you can usually omit the outer brackets. Finally, we get:
>>> dict((m.get(k, k), v) for (k, v) in d.items()) {'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}
There can be quite a lot in one line of code. Some say this is unreadable, but once you get used to it, stretching this code over several lines seems unreadable. Just don't overdo it. Conditional expressions and generator expressions are very powerful, but with great power comes great responsibility. +1 for a good question!