2013-02-11 3 views
9

Nun, die Frage ist im Titel: Wie definiere ich ein Python-Wörterbuch mit unveränderlichen Schlüsseln, aber veränderbaren Werten? Ich kam mit dieser (in Python 2.x) auf:Definieren Sie ein Python-Wörterbuch mit unveränderbaren Schlüsseln, aber änderbaren Werten

class FixedDict(dict): 
    """ 
    A dictionary with a fixed set of keys 
    """ 

    def __init__(self, dictionary): 
     dict.__init__(self) 
     for key in dictionary.keys(): 
      dict.__setitem__(self, key, dictionary[key]) 

    def __setitem__(self, key, item): 
     if key not in self: 
      raise KeyError("The key '" +key+"' is not defined") 
     dict.__setitem__(self, key, item) 

aber es scheint mir, (wenig überraschend) eher schlampig. Ist dies insbesondere sicher, oder besteht die Gefahr, dass einige Schlüssel tatsächlich geändert/hinzugefügt werden, da ich von dict geerbt habe? Danke.

+0

Nun, jemand könnte vermutlich 'dict .__ stitem __()' auf einer Instanz von 'FixedDict' aufrufen, nein? – cdhowie

+2

Sie sollten überprüfen, ob "dict.update" '__setitem__' aufruft - auch wenn dies der Fall ist, bin ich mir nicht sicher, ob dies implementierungsabhängig ist ... – mgilson

+0

(' update' umgeht '__setitem__') – katrielalex

Antwort

10

Betrachten Sie Proxy-dict anstelle von Unterklasse es. Das bedeutet, dass nur die von Ihnen definierten Methoden zulässig sind, anstatt auf die Implementierungen von dict zurückzugreifen.

class FixedDict(object): 
     def __init__(self, dictionary): 
      self._dictionary = dictionary 
     def __setitem__(self, key, item): 
       if key not in self._dictionary: 
        raise KeyError("The key {} is not defined.".format(key)) 
       self._dictionary[key] = item 
     def __getitem__(self, key): 
      return self._dictionary[key] 

Außerdem sollten Sie String-Formatierung statt + verwenden, um die Fehlermeldung zu erzeugen, da sonst wird es für jeden Wert abstürzen, die keine Zeichenfolge ist.

1

Wie Sie verhindern, dass jemand neue Schlüssel hinzufügt, hängt ganz davon ab, warum jemand versucht, neue Schlüssel hinzuzufügen. Wie die Kommentare sagen, gehen die meisten Dictionary-Methoden, die die Schlüssel modifizieren, nicht durch __setitem__, so dass ein .update()-Aufruf neue Schlüssel hinzufügen wird.

Wenn Sie nur erwarten, dass jemand d[new_key] = v verwendet, dann ist Ihre __setitem__ in Ordnung. Wenn sie andere Möglichkeiten zum Hinzufügen von Schlüsseln verwenden, müssen Sie mehr arbeiten. Und natürlich können sie immer diese verwenden, es zu tun sowieso:

dict.__setitem__(d, new_key, v) 

Sie können die Dinge nicht wirklich unveränderlich in Python machen, können Sie nur bestimmte Änderungen stoppen.

11

Das Problem mit direkter Vererbung von dict ist, dass es ziemlich schwierig ist, mit dem vollen dict ‚s Vertrag zu erfüllen (zum Beispiel in Ihrem Fall update Verfahren werden in einer konsistenten Art und Weise nicht verhalten).

Was Sie wollen, ist die collections.MutableMapping zu verlängern:

import collections 

class FixedDict(collections.MutableMapping): 
    def __init__(self, data): 
     self.__data = data 

    def __len__(self): 
     return len(self.__data) 

    def __iter__(self): 
     return iter(self.__data) 

    def __setitem__(self, k, v): 
     if k not in self.__data: 
      raise KeyError(k) 

     self.__data[k] = v 

    def __delitem__(self, k): 
     raise NotImplementedError 

    def __getitem__(self, k): 
     return self.__data[k] 

    def __contains__(self, k): 
     return k in self.__data 

Beachten Sie, dass das Original (verpackt) dict geändert werden, wenn Sie nicht passieren wollen, copy or deepcopy verwenden.

+0

+1 'MutableMapping' ist der Weg, hier zu gehen – katrielalex

Verwandte Themen