寛容な辞書 (KeyError が発生した場合にデフォルト値を返すもの) を作成する方法を考えています。
次のコード例では、KeyError を取得します。例えば
a = {'one':1,'two':2}
print a['three']
取得しないためには、1. 例外をキャッチするか、get を使用する必要があります。
私は自分の辞書でそれをする必要がないようにしたい...
寛容な辞書 (KeyError が発生した場合にデフォルト値を返すもの) を作成する方法を考えています。
次のコード例では、KeyError を取得します。例えば
a = {'one':1,'two':2}
print a['three']
取得しないためには、1. 例外をキャッチするか、get を使用する必要があります。
私は自分の辞書でそれをする必要がないようにしたい...
import collections
a = collections.defaultdict(lambda: 3)
a.update({'one':1,'two':2})
print a['three']
必要に応じて放出3
します。dict
自分自身をサブクラス化してオーバーライドすることもできますが、動作(検索されている正確な欠落キーを無視する)があなたに非常に適している__missing__
場合、それはあまり意味がありません...defaultdict
編集...を除いa
て、つまり、欠落しているキー ( のセマンティクスの一部) を検索するたびに 1 つのエントリが増えることを心配しており、defaultdict
むしろ動作を遅くしてメモリを節約したいと考えています。たとえば、メモリに関しては...:
>>> import sys
>>> a = collections.defaultdict(lambda: 'blah')
>>> print len(a), sys.getsizeof(a)
0 140
>>> for i in xrange(99): _ = a[i]
...
>>> print len(a), sys.getsizeof(a)
99 6284
...元々空だった defaultdict には、検索した以前に欠落していた 99 個のキーがあり、6284 バイトかかります (空だったときは 140 バイトかかりました)。
別のアプローチ...:
>>> class mydict(dict):
... def __missing__(self, key): return 3
...
>>> a = mydict()
>>> print len(a), sys.getsizeof(a)
0 140
>>> for i in xrange(99): _ = a[i]
...
>>> print len(a), sys.getsizeof(a)
0 140
...ご覧のとおり、このメモリのオーバーヘッドを完全に節約できます。もちろん、パフォーマンスは別の問題です。
$ python -mtimeit -s'import collections; a=collections.defaultdict(int); r=xrange(99)' 'for i in r: _=a[i]'
100000 loops, best of 3: 14.9 usec per loop
$ python -mtimeit -s'class mydict(dict):
> def __missing__(self, key): return 0
> ' -s'a=mydict(); r=xrange(99)' 'for i in r: _=a[i]'
10000 loops, best of 3: 92.9 usec per loop
ルックアップ時に(以前に欠落していた)キーを追加するためdefaultdict
、そのようなキーが次にルックアップされるとはるかに高速になりますが、mydict
(その追加を回避するためにオーバーライドされます__missing__
)毎回「欠落したキールックアップのオーバーヘッド」が発生します。
もちろん、どちらの問題(パフォーマンスとメモリフットプリント)を気にするかは、特定のユースケースに完全に依存します。いずれにせよ、トレードオフを認識することは良い考えです!-)
バージョン 2.5 で追加: dict のサブクラスがメソッド __missing__() を定義する場合、キー key が存在しない場合、d[key] 操作はキー key を引数としてそのメソッドを呼び出します。d[key] 操作は、キーが存在しない場合に __missing__(key) 呼び出しによって返されるか発生するものをすべて返すか発生させます。他の操作やメソッドは __missing__() を呼び出しません。__missing__() が定義されていない場合、 KeyError が発生します。__missing__() はメソッドでなければなりません。インスタンス変数にすることはできません。例については、collections.defaultdict を参照してください。
dict
NullUserExceptionによって提案されたサブクラス化の方法は次のとおりです
>>> class forgiving_dict(dict):
... def __missing__(self, key):
... return 3
...
>>> a = forgiving_dict()
>>> a.update({'one':1,'two':2})
>>> print a['three']
3
この回答とAlexの回答の大きな違いの1つは、欠落しているキーが辞書に追加されないことです。
>>> print a
{'two': 2, 'one': 1}
多くのミスを予想する場合、これは非常に重要です
おそらくdefaultdictを使用したいと思うでしょう(少なくともpython2.5が必要だと思います)
from collections import defaultdict
def default(): return 'Default Value'
d = defaultdict(default)
print(d['?'])
コンストラクターに渡される関数は、デフォルト値として何を返すかをクラスに伝えます。その他の例については、ドキュメントを参照してください。
本当に欲しい.setdefault()
のはあまり直感的ではない場合もありますが、それは「指定されたキーを返し、存在しない場合はそのキーをこの値に設定する」メソッドです。
以下は、setdefault()
効果的に使用されている例です。
collection = {}
for elem in mylist:
key = key_from_elem(elem)
collection.setdefault(key, []).append(elem)
これにより、次のような辞書を作成できます{'key1':[elem1, elem3], 'key2':[elem3]}
。キーが既に存在するかどうかを確認し、そのリストを作成するための醜いチェックを行う必要はありません。