2015-05-02 4 views
9

В Python 2 можно сделать следующее:Python 3 карты методы словаря обновления списка других словарей

>> d = {'a':1} 
>> extras = [{'b':2}, {'c':4}] 
>> map(d.update, extras) 
>> d['c'] 
>> 4 

В Python 3 в получу KeyError:

>> d = {'a':1} 
>> extras = [{'b':2}, {'c':4}] 
>> map(d.update, extras) 
>> d['c'] 
>> KeyError: 'c' 

Я хотел бы добиться такого же поведения в Python 3, как в Python 2.

Я понимаю, что карта в Python 3 вернет итератор (ленивая оценка и еще много чего), которая должна быть повторена для словаря t o быть обновленным.

Я предположил, что ключевой поиск d['c'] вызовет итерацию карты как-то, что не так.

Есть ли питонический способ достичь этого поведения, не записывая цикл for, , который я считаю подробным по сравнению с картой.

Я думал об использовании списковых:

>> d = {'a':1} 
>> extras = [{'b':2}, {'c':4}] 
>> [x for x in map(d.update, extras)] 
>> d['c'] 
>> 4 

Но это, кажется, не вещий.

+1

'списка (карта (d.update, дополнительной))' заставят итератор потребляться – jonrsharpe

+3

The вещего способом * это * использовать для цикла!Использование карты (или понимания списка) для ее побочных эффектов, а не ее результатов, определенно * не * pythonic. –

ответ

7

Как вы заметили, map в Python 3 создает итератор, который не делает (само по себе) вызывать любые update s произойти:

>>> d = {'a': 1} 
>>> extras = [{'b':2}, {'c':4}] 
>>> map(d.update, extras) 
<map object at 0x105d73c18> 
>>> d 
{'a': 1} 

Чтобы заставить map быть полностью оценены, вы может передать его list явно:

>>> list(map(d.update, extras)) 
[None, None] 
>>> d 
{'a': 1, 'b': 2, 'c': 4} 

Однако, как соответствующий раздел What's new in Python 3 помещает это:

Особенно сложно это map() вызывается для побочных эффектов функции ; правильное преобразование состоит в использовании регулярного цикла for (так как создание списка будет просто расточительным).

В вашем случае, это будет выглядеть так:

for extra in extras: 
    d.update(extra) 

, который не приводит к ненужному списка None.

+0

, что для цикла было просто укусить меня! спасибо в любом случае – mattgathu

+1

Примечание: вместо 'list' можно использовать' collections.deque (iterable, maxlen = 0) ', чтобы использовать' iterable' без памяти. Это также выполняет только один байт-код, поэтому должно быть немного более эффективным по времени, чем явное 'for', по крайней мере, в CPython. – Bakuriu

+0

@Bakuriu интересно, я бы не подумал об этом; Я не знал, что 'deque' * может * иметь нулевую максимальную длину! – jonrsharpe

1

Наряду с объяснением @ jonrsharpe, что объясняет проблему ясно В Python 3 вы можете использовать collections.ChainMap для таких задач:

>>> from collections import ChainMap 
>>> chain=ChainMap(d, *extras) 
>>> chain 
ChainMap({'a': 1}, {'b': 2}, {'c': 4}) 
>>> chain['c'] 
4 

Но обратите внимание, что если есть повторяющиеся ключи, значение от первого отображения получить используемый.

Узнайте больше о преимуществах использования ChainMap: What is the purpose of collections.ChainMap?

Смежные вопросы