Python: как изменить подмножество значений словаря?

У меня уже есть словарь d. Я хочу изменить только значения определенного типа. Например, я хочу заменить строки их длинами.

Скучный способ сделать это с помощью цикла for:

for k,v in d.items():
    if isinstance(v, str):
        d[k] = len(v)

Но разве зацикливание не медленное?
Это можно сделать с пониманием. Я думаю, что это эквивалентно приведенному выше:

d = {k: len(v) if isinstance(v, str) else v for k,v in d.items()}

Я попробовал это с картой, но они не работают (очевидно, потому что я не понимаю кое-что о распаковке кортежей в Python 3):

d = dict(map(lambda k,v: (k, len(v) if isinstance(v, str) else v), d.items()))
d = dict(map(lambda (k,v): (k, len(v) if isinstance(v, str) else v), d.items()))

Кажется, это работает, но становится большим и уродливым:

dict(map(lambda kv: (kv[0], len(kv[1]) if isinstance(kv[1], str) else kv[1]), d.items()))

Похоже, что такого рода операции будут обычным явлением, но я не могу найти конкретных ответов.
Каков правильный, Pythonic и производительный способ сделать это?


person Jacktose    schedule 09.03.2018    source источник
comment
Ваше dict понимание правильное, и imho - это питонический способ добиться этого.   -  person Cory Kramer    schedule 10.03.2018
comment
Цикл for не создает новый словарь и заменяет только те элементы, которые имеют строку в качестве значения. Понимание создает новый словарь и устанавливает каждый элемент, включая те, которые имеют нестроковое значение в качестве значения. Вы спрашиваете, медленный ли цикл, но когда вам нужно иметь дело с каждым элементом в наборе значений, альтернативы нет. Понимание — это не магия; это тоже петля.   -  person Paul Cornelius    schedule 10.03.2018
comment
@PaulCornelius Ой, а не магия? Нет, я просто подумал, может быть, это было более оптимизировано за кулисами. Так что цикл for может быть быстрее? Или использует меньше памяти?   -  person Jacktose    schedule 10.03.2018
comment
При прочих равных вы всегда предпочтете понимание циклу for. Но если у вас в словаре миллион элементов, и только два из них являются строками, понимание выполнит 999 998 ненужных копий, тогда как цикл for просто заменит 2 значения. Таким образом, правило типа comprehension=fast for loop=slow слишком простое.   -  person Paul Cornelius    schedule 10.03.2018
comment
@ P1h3r1e3d13 в этом случае цикл for определенно будет использовать меньше памяти, действительно, он использует постоянный объем памяти, а не понимание, для которого требуется O (n) памяти. Но даже если бы ваш цикл был полностью эквивалентен пониманию, то есть он создавал бы новый словарь вместо изменения существующего, вы можете ожидать лишь незначительного прироста скорости. Понимания следует предпочитать в основном для удобства чтения.   -  person juanpa.arrivillaga    schedule 10.03.2018
comment
IOW: циклы for на языке Python.   -  person juanpa.arrivillaga    schedule 10.03.2018


Ответы (1)


У вас уже есть ответ, и CoryKramer уже упомянул его.

d = {k: len(v) if isinstance(v, str) else v for k,v in d.items()}

Это делает это, и это самый чистый способ.

person A. Stewart    schedule 09.03.2018