2013-02-11 12 views
9

問題はタイトルにあります:不変キーを持つが変更可能な値を持つPython辞書を定義するにはどうすればいいですか?私は、この(のpython 2.xで)を思い付いた:不変キーではあるが変更可能な値を持つPython辞書を定義する

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) 

が、それは(当然ながら)私にはかなりずさんに見えます。特に、私はdictを継承しているので、これは安全か、実際にキーを変更/追加するリスクはありますか?おかげさまで

+0

誰かがおそらく 'FixedDict'のインスタンスで' dict .__ setitem __() 'を呼び出すことができますか? – cdhowie

+2

'dict.update'が' __setitem__'を呼び出すことを確認する必要があります - もしそれがあっても、それが実装依存かどうかわかりません... – mgilson

+0

( 'update'は' __setitem__'をバイパスします。 ) – katrielalex

答えて

10

サブクラス化する代わりにdictをプロキシ処理することを検討してください。これは、あなたが定義したメソッドだけが、dictの実装に落ちるのではなく、許可されることを意味します。それ以外の場合は、文字列ではありません任意の値のためにクラッシュしてしまいますので、

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] 

また、あなたは、エラーメッセージを生成する代わりに+の文字列フォーマットを使用する必要があります。

1

誰かが新しいキーを追加しないようにする方法は、誰かが新しいキーを追加しようとする理由によってまったく異なります。コメント状態として、キーを変更するほとんどの辞書メソッドは__setitem__を通過しないので、.update()呼び出しで新しいキーが追加されます。

誰かがd[new_key] = vを使用すると予想される場合は、__setitem__は問題ありません。他の方法でキーを追加することができれば、より多くの作業をする必要があります。そしてもちろん、彼らは常に、とにかくそれを行うには、これを使用することができます:あなたがPythonで物事が本当に不変にすることはできません

dict.__setitem__(d, new_key, v) 

、あなただけの特定の変更を停止することができます。

11

dictからの直接継承の問題は、完全なdictの契約(例えば、あなたのケースでは、updateメソッドは一貫した方法で動作しません)に準拠するのが非常に難しいということです。あなたはそれがcopy or deepcopyを使用し、起こるしたくない場合は、元の(ラップ)辞書が変更されること

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 

注:あなたが欲しい

は、collections.MutableMappingを拡張することです。

+0

+1 'MutableMapping'はここに行く方法です – katrielalex

関連する問題