2009-03-16 2 views
66

Perlで何度も何度もやっています。Pythonでdictsのdictを初期化する最良の方法は何ですか?

$myhash{foo}{bar}{baz} = 1 

これをPythonに変換するには?これまで私は持っている:

if not 'foo' in myhash: 
    myhash['foo'] = {} 
if not 'bar' in myhash['foo']: 
    myhash['foo']['bar'] = {} 
myhash['foo']['bar']['baz'] = 1 

良い方法はありますか?

+0

エーム、確かに他の5日前に尋ねられたこれらの両方は4歳です... –

答えて

83
class AutoVivification(dict): 
    """Implementation of perl's autovivification feature.""" 
    def __getitem__(self, item): 
     try: 
      return dict.__getitem__(self, item) 
     except KeyError: 
      value = self[item] = type(self)() 
      return value 

テスト:

a = AutoVivification() 

a[1][2][3] = 4 
a[1][3][3] = 5 
a[1][2]['test'] = 6 

print a 

出力:

{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}} 
+3

次のような動作をサポートするように拡張できますか?a [1] [2] [3] + = some_value。したがって、キーが事前に存在しなかった場合、a [1] [2] [3]は型のデフォルト値(some_value)で初期化されますか? –

+4

この関数には、存在しないキーを取得しようとするとキーが作成されるという副作用があります。通常、キーまたはサブキーを同時に設定していた場合は、キーを自動作成したいだけです。 –

+0

割り当て変数を作成する方法もありますか?だから、 'var = [1,2,3]'を与えれば 'a [var] = 1'のようになり、' a [1] [2] [3] = 1'に拡張することができます。 – PascalVKooten

2

私は直訳は以下のようになり推測:

mydict = {'foo' : { 'bar' : { 'baz':1}}} 

呼び出し:

>>> mydict['foo']['bar']['baz'] 

は、しかし、私には少し総額を見えること、あなたに1

を与えます。

(私も、何のperlの男だので、私はあなたのperlが何をするかで推測している)ような

+1

それは、初期化時にのみ、しかし、右の作品ですか? – mike

+0

私はあなたが何を意味するか分かりません。 – Dana

+0

@Danaのように、実行時に新しい値をmydictに追加するのではなく、 –

2

ネストされた辞書は、(しばしば)貧しいマンオブジェクトと呼ばれます。 はい、含意があり、ピトンオブジェクト指向の性質と相関する可能性があります。

12

それはdictsの辞書にする必要がある理由はありますか?その特定の構造のための説得力のある理由はありません場合は、単にタプルを持つインデックス辞書をことができます:あなたはタプルキーで辞書を初期化しますが、取得/設定するときに、あなたがそれらを省略することができるかどう

mydict = {('foo', 'bar', 'baz'):1} # Initializes dict with a key/value pair 
mydict[('foo', 'bar', 'baz')]  # Returns 1 

mydict[('foo', 'unbar')] = 2  # Sets a value for a new key 

括弧が必要とされています[]使用して値:あなたが必要とするネストの量が固定されている場合は、collections.defaultdictは素晴らしいです

mydict = {}      # Initialized the dict 
mydict['foo', 'bar', 'baz'] = 1 # Sets a value 
mydict['foo', 'bar', 'baz']  # Returns 1 
+0

カッコを省略することはできますか?カンマはタプル演算子であり、あいまいなグループ化が必要な場合のみ必要ですか? – Kiv

+0

説明を追加しました。 – zweiterlinde

+0

3つではなく1つの参照があるため、実際にはネストされた辞書よりも高速です。 – ChaimG

86

2深いネスト:

myhash = collections.defaultdict(lambda : collections.defaultdict(dict)) 
myhash[1][2][3] = 4 
myhash[1][3][3] = 5 
myhash[1][2]['test'] = 6 

編集:MizardXは我々が完全な一般性を得ることができることを指摘するあなたは、ネストの別のレベルに行きたい場合は

myhash = collections.defaultdict(dict) 
myhash[1][2] = 3 
myhash[1][3] = 13 
myhash[2][4] = 9 

することは、あなたのような何かをする必要がありますシンプルな機能:

import collections 
def makehash(): 
    return collections.defaultdict(makehash) 

今、私たちが行うことができます。

myhash = makehash() 
myhash[1][2] = 4 
myhash[1][3] = 8 
myhash[2][5][8] = 17 
# etc 
+4

またはdef makehash():return collections.defaultdict(makehash); myhash = makehash() –

+0

"従来の"再帰関数には何の問題もありませんが、直感的ではないことがあります。奇妙なとりあえずありがとう! –

+1

ありがとうございます。そのラムダ:defaultdict()は私が必要としたものです。 – wheaties

関連する問題