36

defaultdict(set)非常に大きなデータ構造に内部マッピングを設定するために使用しています。データが取り込まれた後、構造全体 (マッピングを含む) がクライアント コードに公開されます。その時点で、誰もマッピングを変更したくありません。

そして、誰も意図的にそうしません。しかし、クライアント コードが存在しない要素を誤って参照する場合があります。その時点で、通常の辞書は を発生させますKeyErrorが、マッピングはdefaultdictであるため、そのキーで新しい要素 (空のセット) を作成するだけです。すべてが静かに行われるため、これを把握するのは非常に困難です。しかし、これが起こらないようにする必要があります (セマンティクスは実際には壊れませんが、マッピングは巨大なサイズに成長します)。

私は何をすべきか?これらの選択肢が表示されます:

  1. マッピングでディクショナリ ルックアップが実行される現在および将来のクライアント コード内のすべてのインスタンスを検索し、mapping.get(k, {})代わりに変換します。これはただひどいです。

  2. defaultdictデータ構造が完全に初期化された後、それを に変換して「フリーズ」しdictます。(実際には凍結されていないことはわかっていますが、クライアント コードが実際にはmapping[k] = v.

  3. インターフェイスにラップdefaultdictdictます。それを行うエレガントな方法は何ですか?残念ながら、パフォーマンスへの影響は大きいかもしれません (このルックアップはタイトなループで頻繁に使用されます)。

  4. defaultdictすべての機能を「シャットダウン」するメソッドをサブクラス化して追加しdefaultdict、通常の のように動作させますdict。上記の 3 の変形ですが、それより速いかどうかはわかりません。そして、実装の詳細に頼らずに実行できるかどうかはわかりません。

  5. データ構造でregulardictを使用し、そこにあるすべてのコードを書き直して、要素が辞書にあるかどうかを最初に確認し、そうでない場合は追加します。良くない。

4

3 に答える 3

57

defaultdictドキュメントによるとdefault_factory

default_factory属性がNoneの場合、これにより、キーを引数としてKeyError例外が発生します。

defaultdictのdefault_factoryを設定した場合はどうなりますNoneか?例えば、

>>> d = defaultdict(int)
>>> d['a'] += 1
>>> d
defaultdict(<type 'int'>, {'a': 1})
>>> d.default_factory = None
>>> d['b'] += 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'b'
>>> 

これが最善のアプローチかどうかはわかりませんが、うまくいくようです。

于 2012-11-20T02:29:33.173 に答える
0

dict への参照を保持するクラスを作成し、setitem ()を防ぐことができます

from collections import Mapping

class MyDict(Mapping):
    def __init__(self, d):
        self.d = d;

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

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

    def __setitem__(self, k, v):
        if k not in self.d.keys():
            raise KeyError
        else:
            self.d[k] = v
于 2012-11-20T02:48:27.687 に答える