2014-12-16 8 views
9

Mam słownika:Jak przekazać słownik z dodatkowymi elementami w pythonie?

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

(uwaga: Mój słownik nie jest faktycznie liczb na łańcuchy)

ja przejściu tego słownika do funkcji, która wzywa do niego. Często używam słownika do różnych funkcji. Jednak przy okazji chcę wysłać w big_dict z dodatkowym kluczem: parę rzeczy tak, że słownik Chcę wysłać byłoby równoznaczne z:

big_dict[1001]="1001" 

Ale ja nie chcę faktycznie dodać wartość do słownika. Mógłbym zrobić kopię słownika i dodać go tam, ale chciałbym uniknąć cykli pamięci + procesora, który by zużył.

Kod Obecnie mam to:

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

Chociaż to działa, wydaje się raczej kludgy.

Gdyby to był ciąg zrobiłbym:

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

Czy istnieje odpowiednik sposób to zrobić ze słownikiem?

+0

Czy dodatkowa para klucz-wartość zawsze jest taka sama? – wnnmaw

+0

W tym konkretnym przypadku, tak, ale chciałbym wiedzieć, jak to zrobić w ogólnym przypadku. – Mitch

Odpowiedz

7

Jak podkreślił Veedrac w his answer, ten problem został już rozwiązany w Pythonie 3.3+ w postaci klasy ChainMap:

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

Jeśli nie masz Python 3.3 należy użyć backportu i jeśli z jakiegoś powodu nie chcą, a następnie poniżej można zobaczyć jak zaimplementować to sam :)


można stworzyć opakowanie, podobnie do tego:

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] 

    # ... 

Oczywiście należy podać wszystkie inne metody dict lub użyć UserDict jako klasy bazowej, co powinno to uprościć.

a następnie używać go tak:

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

ten można łatwo rozszerzyć na cały dodatkowego słownika „specjalnych” kluczy i wartości, a nie tylko pojedynczy element dodatkowy.


Możesz również rozszerzyć to podejście, aby osiągnąć coś podobnego jak w przykładzie wyrażenie:

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) 

i używać go tak:

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

Więc w przypadkach, w których chcę użyć "zmienionego" dykta, użyłbym klasy 'DictAdditional..' i używaj zwykłego dyktowania do wszystkiego innego, tak? – Mitch

+0

@musher Tak, dokładnie. Owijka imituje oryginalny dict, nieznacznie zmieniając zachowanie dla specjalnej pary klucz/wartość. Można nawet utworzyć klasę 'SpecialKeyValuePair' i zastąpić jej operator' + ', więc możesz mieć prawie taką samą notację, jak w przypadku łańcucha. – BartoszKP

0

Jest to nieco irytujące też ale możesz po prostu mieć funkcję przyjmującą dwa parametry, z których jeden to big_dict, a drugi jest tymczasowym słownikiem, utworzonym tylko dla funkcji (czyli coś takiego jak fxn(big_dict, {1001,'1001'})).Wtedy możesz uzyskać dostęp do obu słowników bez zmiany pierwszego i bez kopiowania big_dict.

1

Możesz dodać dodatkowy klucz-wartość pary opuszczającej oryginalnego słownika jako takie tak:

>>> 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

To jest fajne. Czy możesz zrobić to samo z 'iteritems' bez importowania' itertools'? –

+0

Spowoduje to utworzenie kopii dokumentu, którego użytkownik chce uniknąć. Czy jest szybszy niż dict.copy? – tdelaney

3

jeśli jesteś na 3.3+, wystarczy użyć ChainMap. W przeciwnym razie użyj backport.

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

Jakąkolwiek wskazówkę, gdzie znajdę backport ChainMap for 3.1? Lub ogólnie – Mitch

+0

@Mitch Jeśli nie możesz znaleźć czegoś na PyPI, po prostu [skopiuj kod z 3.3/3.4] (https://github.com/python/cpython/blob/64c0b898c22d3e89ea03335c75580f37e606787d/Lib/collections/__init__.py # L814). – Veedrac

Powiązane problemy