1

I have a code that was working in python 2, but now in python 3 raises the error "TypeError: keyword arguments must be strings". It is the first line of a function, so shouldn't be a problem with previous code.

   map = collections.defaultdict(lambda: 'blinn',**{0: 'constant', 1:'lambert'})

Maybe someone could also explain me what this line of code is doing and what is the "map" object that creates. I have found Python defaultdict and lambda but I still have problems in understanding this line of code.

Community
  • 1
  • 1
user3555654
  • 85
  • 3
  • 8

1 Answers1

2

The **{0: 'constant', 1:'lambert'} passes in two default key-value pairs as keyword arguments to the defaultdict() constructor. However, the same constructor would treat a dictionary as the second argument as defaults too.

As such, the ** can be omitted altogether, in both 2 and 3:

collections.defaultdict(lambda: 'blinn', {0: 'constant', 1:'lambert'})

Demo in Python 2, showing you get the same output:

>>> import sys
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=12, releaselevel='final', serial=0)
>>> import collections
>>> collections.defaultdict(lambda: 'blinn', **{0: 'constant', 1:'lambert'})  == collections.defaultdict(lambda: 'blinn', {0: 'constant', 1:'lambert'})
True
>>> collections.defaultdict(lambda: 'blinn', **{0: 'constant', 1:'lambert'})
defaultdict(<function <lambda> at 0x102426410>, {0: 'constant', 1: 'lambert'})
>>> _[0]
'constant'
>>> collections.defaultdict(lambda: 'blinn', {0: 'constant', 1:'lambert'})
defaultdict(<function <lambda> at 0x102426410>, {0: 'constant', 1: 'lambert'})
>>> _[0]
'constant'

and in Python 3:

>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=6, micro=0, releaselevel='beta', serial=3)
>>> import collections
>>> collections.defaultdict(lambda: 'blinn', {0: 'constant', 1:'lambert'})
defaultdict(<function <lambda> at 0x10e3589d8>, {0: 'constant', 1: 'lambert'})
>>> _[0]
'constant'
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Why does defaultdict accept not string keyword arguments? Doesn't it breaks consistency? – grzgrzgrz3 Nov 21 '16 at 19:24
  • @grzgrzgrz3 keyword arguments are always strings but Python 2 did not enforce this when using `**kw` In a call *and* the callable accepts arbitrary keyword arguments. Python 3 fixed this. – Martijn Pieters Nov 21 '16 at 19:54
  • As i can see in python2 it applies only to objects based on dict. Other objects raising `TypeError`. – grzgrzgrz3 Nov 21 '16 at 21:15
  • @grzgrzgrz3: yes, sorry, Python 2 inconsistently enforces it; C objects could still accept them, Python functions won't. So `dict(**{0: 'foo'})` works, but `def foo(**kw): pass`, then `foo(**{0: 'foo'})` doesn't, because the Python function won't accept them. – Martijn Pieters Nov 21 '16 at 21:19