2014-12-16 11 views
9

Ho un dizionario:Come passare un dizionario con elementi aggiuntivi in ​​python?

big_dict = {1:"1", 
      2:"2", 
      ... 
      1000:"1000"} 

(Nota: Il mio dizionario non è in realtà i numeri in stringhe)

sto passando questo dizionario in una funzione che lo richiede. Uso spesso il dizionario per diverse funzioni. Tuttavia, a volte voglio mandare in big_dict con una chiave in più: coppia di voce tale che il dizionario voglio inviare sarebbe equivalente a:

big_dict[1001]="1001" 

Ma io non voglio realtà aggiungere il valore al dizionario. Potrei fare una copia del dizionario e aggiungerla lì, ma vorrei evitare i cicli di memoria + CPU che questo consumerebbe.

Il codice ho attualmente è:

big_dict[1001]="1001" 
function_that_uses_dict(big_dict) 
del big_dict[1001] 

Anche se questo funziona, sembra piuttosto kludgy.

Se questa fosse una stringa farei:

function_that_uses_string(myString + 'what I want to add on') 

C'è un modo equivalente di fare questo con un dizionario?

+0

La coppia di valori-chiave in eccesso è sempre la stessa? – wnnmaw

+0

In questo caso particolare, sì, ma mi piacerebbe sapere come farlo anche per il caso generale – Mitch

risposta

7

Come sottolineato da Veedrac in his answer, questo problema è già stato risolto in Python 3.3+ nella forma della classe ChainMap:

function_that_uses_dict(ChainMap({1001 : "1001"}, big_dict)) 

Se non si dispone di Python 3.3 è necessario utilizzare un backport e se per qualche motivo non si vuole, allora qui sotto potete vedere come implementare da soli :)


è possibile creare un involucro, in modo simile a questo:

class DictAdditionalValueWrapper: 
    def __init__(self, baseDict, specialKey, specialValue): 
     self.baseDict = baseDict 
     self.specialKey = specialKey 
     self.specialValue = specialValue 

    def __getitem__(self, key): 
     if key == self.specialKey: 
      return self.specialValue 

     return self.baseDict[key] 

    # ... 

È necessario fornire tutti gli altri metodi dict, oppure utilizzare UserDict come classe base, che dovrebbe semplificare questo.

e quindi utilizzare in questo modo:

function_that_uses_dict(DictAdditionalValueWrapper(big_dict, 1001, "1001")) 

Questo può essere facilmente estesa a tutta una dizionario aggiuntivo di chiavi "speciali" e di valori, non solo singolo elemento aggiuntivo.


È inoltre possibile estendere questo approccio per raggiungere qualcosa di simile, come nel tuo esempio stringa:

class AdditionalKeyValuePair: 
    def __init__(self, specialKey, specialValue): 
     self.specialKey = specialKey 
     self.specialValue = specialValue 

    def __add__(self, d): 
     if not isinstance(d, dict): 
      raise Exception("Not a dict in AdditionalKeyValuePair") 

     return DictAdditionalValueWrapper(d, self.specialKey, self.specialValue) 

e usarlo in questo modo:

function_that_uses_dict(AdditionalKeyValuePair(1001, "1001") + big_dict) 
+0

Quindi, nel caso in cui voglio usare il comando 'alterato', userei la classe 'DictAdditional..' e usa la dict regolare per tutto il resto, sì? – Mitch

+0

@musher Sì, esattamente. Il wrapper imita il dict originale, alterando leggermente il comportamento per la coppia chiave/valore speciale. Potresti anche creare una classe 'SpecialKeyValuePair', e sovrascrivere il suo operatore' + ', così potresti avere quasi la stessa notazione della stringa. – BartoszKP

0

Questo è un po 'fastidioso troppo, ma si potrebbe semplicemente fare in modo che la funzione abbia due parametri, uno dei quali è big_dict, e un altro è un dizionario temporaneo, creato solo per la funzione (quindi qualcosa come fxn(big_dict, {1001,'1001'})).Quindi è possibile accedere a entrambi i dizionari senza modificare il primo e senza copiare big_dict.

1

È possibile aggiungere l'extra chiave-valore coppia lasciando dizionario originale in quanto tale, in questo modo:

>>> def function_that_uses_bdict(big_dict): 
... print big_dict[1001] 
... 
>>> dct = {1:'1', 2:'2'} 
>>> function_that_uses_bdict(dict(dct.items()+[(1001,'1001')])) 
1001 
>>> dct 
{1: '1', 2: '2'} # original unchanged 
+0

Questo è bello. Puoi fare lo stesso con 'iteritems' senza importare' itertools'? –

+0

Questo fa una copia del dict che l'utente sta tentando di evitare. È più veloce di dict.copy? – tdelaney

3

Se siete su 3.3+, basta usare ChainMap. Altrimenti usa un backport.

new_dict = ChainMap({1001: "1001"}, old_dict) 
+0

Qualsiasi indizio in cui troverei un backport di ChainMap per 3.1? O in generale – Mitch

+0

@Mitch Se non trovi qualcosa su PyPI, solo [copia il codice da 3.3/3.4] (https://github.com/python/cpython/blob/64c0b898c22d3e89ea03335c75580f37e606787d/Lib/collections/__init__.py # L814). – Veedrac

Problemi correlati