2015-05-02 5 views
9

In Python 2 Ich kann Folgendes tun:Python 3 map Wörterbuch Update-Methode auf eine Liste von anderen Wörterbuch

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

In Python 3 in eine KeyError erhalten:

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

Ich mag würde zu erreichen das gleiche Verhalten in Python 3 wie in Python 2.

Ich verstehe, dass Karte in Python 3 wird einen Iterator (Lazy Evaluation und whatnot), die für das Wörterbuch t iteriert werden muss o aktualisiert werden.

Ich hatte angenommen, die d['c'] Schlüsselsuche würde die Karteniteration irgendwie auslösen, was nicht der Fall ist.

Gibt es einen pythonischen Weg, um dieses Verhalten zu erreichen, ohne eine for-Schleife zu schreiben, , die ich im Vergleich zu Karte ausführlich finde.

Ich habe daran gedacht, mit Listenkomprehensionen:

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

Aber es funktioniert nicht pythonic scheinen.

+1

'Liste (Karte (d.update, Extras))' die Iterator zwingen – jonrsharpe

+3

Die pythonic Weise verbraucht werden * ist * eine for-Schleife zu verwenden!Die Verwendung der Karte (oder eines Listenverständnisses) für ihre Nebenwirkungen und nicht ihre Ergebnisse ist definitiv * nicht * pythonisch. –

Antwort

7

Wie Sie merken, map in Python 3 erzeugt einen Iterator, der nicht der Fall ist (in sich selbst) verursachen keine update s auftreten:

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

Um die map zu zwingen vollständig ausgewertet werden, Sie ausdrücklich könnte es zu list passieren:

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

da jedoch dem entsprechenden Abschnitt What's new in Python 3 sagt:

Besonders heikel ist map() für die Nebenwirkungen der Funktion aufgerufen; Die richtige Umwandlung ist eine regelmäßige for Schleife (seit Erstellen einer Liste wäre einfach verschwenderisch).

In Ihrem Fall würde dies wie folgt aussehen:

for extra in extras: 
    d.update(extra) 

die in einer unnötigen Liste von None führt nicht.

+0

dass für for loop wurde gerade gehen mich beißen! danke trotzdem – mattgathu

+1

Hinweis: anstelle von 'list' kann man' collections.deque (iterable, maxlen = 0) 'verwenden, um' iterable' zu ​​konsumieren, ohne Speicher zu verbrauchen. Dies führt auch nur einen Bytecode aus und sollte daher etwas effizienter sein als ein explizites 'for' in CPython. – Bakuriu

+0

@Bakuriu interessant, hätte ich nicht daran gedacht, das zu tun; Ich wusste nicht, dass eine "Deque" eine maximale Länge von Null haben könnte! – jonrsharpe

1

Neben der Erklärung der @ jonrsharpe, die das Problem klar In Python 3 erklärt Sie collections.ChainMap für solche Aufgaben verwenden können:

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

Aber beachten Sie, dass, wenn es doppelte Schlüssel, die Werte aus der ersten Mapping erhalten benutzt.

Lesen Sie mehr über die Vorteile von ChainMap mit: What is the purpose of collections.ChainMap?

Verwandte Themen