Problems with general mutable?

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

Output:

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

As you can see, tags1they tags2actually refer to the same list that is not intended. cnt1and cnt2work fine.

How can I implement set_if_not_thereto create a copiesmutable, but only if necessary? That is, if the default value is a "scalar" (int, string None,, ...), a copy is not required, but a copy is required for lists and dicts.

+4
source share
2 answers

Use the factory function instead of the default value:

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()

and pass in callable characters (e.g. functions or lambdas or default types):

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

int()returns 0, list()returns a new empty list.

, 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']}
+9

copy.deepcopy.

import copy
def set_if_not_there(d, fields, default_value=None):
    for field in fields:
        if not field in d:
            d[field] = copy.deepcopy(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': [], 'cnt2': 0, 'cnt1': 1, 'tags1': ['work']}

, , , . :

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

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

print d

:

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

**, :

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

d = { }

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

+2

All Articles