1

I'm trying to create an inner dictionary that has values stored in a list or set object (using a set for this example).

t = [('Jobs', set()), ('Titles', set())]
inn_d = lambda: dict(t)

And creating a default dictionary and passing inn_d into that.

d = defaultdict(inn_d)

When creating the entries for d and the outer keys, both values for each inner key gets updated.

d['A']['Jobs'].add('Cook')
d['B']['Titles'].add('President')
d
defaultdict(<function <lambda> at 0x0000016691157DC0>, {'A': {'Jobs': {'Cook'}, 'Titles': {'President'}}, 'B': {'Jobs': {'Cook'}, 'Titles': {'President'}}})

When it should be

defaultdict(<function <lambda> at 0x0000016691157DC0>, {'A': {'Jobs': {'Cook'}, 'Titles': set()}, 'B': {'Jobs': set(), 'Titles': {'President'}}})

I know that the same set object for both Jobs and Titles is getting called - I am not sure how to create a new set object when creating the inner dictionary.

Thank you for your help.

wjandrea
  • 28,235
  • 9
  • 60
  • 81

1 Answers1

2

Create a new one each time like this:

def inn_d():
    return {'Jobs': set(), 'Titles': set()}

By the way, named lambdas are bad practice.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • It looks like I get the same result. Is this the right way to go about it with this? `inner = inn_d()` `d = defaultdict(lambda: inner)` – nalgenebottle Nov 11 '21 at 21:07
  • 1
    @user2059363 No, `d = defaultdict(inn_d)`. You can also check out [my full test code](https://gist.github.com/wjandrea/b89241ae6a6d9df1a78ae036c8ef2bf2). – wjandrea Nov 11 '21 at 21:12
  • Ahh I see. Thank you very much. Is my understanding correct that by not including the parentheses in `d = defaultdict(inn_d)`, we make `inn_d` callable instead of returning the dict, which returns a new object every time it is called? – nalgenebottle Nov 11 '21 at 21:15
  • 1
    @user2059363 np! I'm not sure what you're asking though. `inn_d` is already callable since it's a function, and dicts are not callable. – wjandrea Nov 11 '21 at 21:17
  • Basically `inn_d` which returns `` and `inn_d()` which returns `{'Jobs': set(), 'Titles': set()}`, the latter which still updates all values in each key and (from my little understanding) is because `inn_d()` returns the same object? - if that makes sense... – nalgenebottle Nov 11 '21 at 21:20
  • Looks like it's not possible to create `d = default(inn_d())` this way anyway, as I get `TypeError: first argument must be callable or None` – nalgenebottle Nov 11 '21 at 21:21
  • 1
    @user2059363 `inn_d()` returns a new dict each time, but if you capture its return value like you did with `inner = inn_d()`, `lambda: inner` will always return the same dict. – wjandrea Nov 11 '21 at 21:23
  • Makes sense. Learned so much from just this use case, thanks a bunch – nalgenebottle Nov 11 '21 at 21:30
  • @nalgene np! Check out [Facts and myths about Python names and values](https://nedbatchelder.com/text/names.html) by Ned Batchelder to start wrapping your head around how it really works – wjandrea Nov 11 '21 at 21:35