4
def set_if_not_there(d, fields, default_value=None):
    for field in fields:
        if not field in d:
            d[field] = default_value

d = { }

set_if_not_there(d, ['cnt1', 'cnt2'], 0)
set_if_not_there(d, ['tags1', 'tags2'], [])

d['cnt1'] += 1
d['tags1'].append('work')

print d

出力は次のとおりです。

{'tags2': ['work'], 'cnt2': 0, 'cnt1': 1, 'tags1': ['work']}

ご覧のとおり、実際には同じリストを参照していますがtags1tags2これは意図したものではありません。cnt1正常にcnt2動作しています。

ミュータブルset_if_not_thereを作成するように実装するにはどうすればよいですか?copiesつまり、デフォルト値が「スカラー」(int、string、None...) の場合、コピーは必要ありませんが、リストと辞書の場合はコピーが必要です。

4

2 に答える 2

9

デフォルト値の代わりにファクトリ関数を使用します。

def set_if_not_there(d, fields, default_factory=None):
    if default_factory is None:
        default_factory = lambda: None
    for field in fields:
        if not field in d:
            d[field] = default_factory()

callable を渡します (関数、ラムダ、または既定の型など):

set_if_not_there(d, ['cnt1', 'cnt2'], int)
set_if_not_there(d, ['tags1', 'tags2'], list)

int()を返し0list()新しい空のリストを返します。

これはcollections.defaultdict()、たとえば、標準ライブラリ タイプも同様です。

デモ:

>>> d = {}
>>> set_if_not_there(d, ['cnt1', 'cnt2'], int)
>>> set_if_not_there(d, ['tags1', 'tags2'], list)
>>> d['cnt1'] += 1
>>> d['tags1'].append('work')
>>> print d
{'tags2': [], 'cnt2': 0, 'cnt1': 1, 'tags1': ['work']}
于 2013-10-13T09:38:39.200 に答える