4

I have dict comprehension with lambda function and scalar:

d = {k: lambda x : x.sum() if 'a' in k else 'yes' for k in ['bac','sss','asa']}
print (d)
{'bac': <function <dictcomp>.<lambda> at 0x00000000031891E0>, 
 'sss': <function <dictcomp>.<lambda> at 0x000000000D887EA0>, 
 'asa': <function <dictcomp>.<lambda> at 0x000000000D887B70>}

If want both scalars it working nice:

d = {k: 'no' if 'a' in k else 'yes' for k in ['bac','sss','asa']}
print (d)
{'bac': 'no', 'sss': 'yes', 'asa': 'no'}

Expected output - combination of scalars and lambda function:

print (d)
{'bac': <function <dictcomp>.<lambda> at 0x00000000031891E0>, 
 'sss': 'yes', 
 'asa': <function <dictcomp>.<lambda> at 0x000000000D887B70>}

What is happening? Why it is not working? What is the correct approach?

Rahul Agarwal
  • 4,034
  • 7
  • 27
  • 51
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
  • 1
    `d = {k: (lambda x : x.sum()) if 'a' in k else 'yes' for k in ['bac','sss','asa']}` works (wrapping lambda in parentheses) but I don't know why. Presumably some of the rest of the expression gets wrapped up in lambda in your current approach. – roganjosh Jan 22 '19 at 13:08

2 Answers2

5

Your syntax is parsed as follows (note the location of the parentheses):

{k: lambda x : (x.sum() if 'a' in k else 'yes') for k in ['bac','sss','asa']}
#              ^                              ^

You want:

{k: (lambda x : x.sum()) if 'a' in k else 'yes' for k in ['bac','sss','asa']}
#   ^                  ^

This is because lambda has lower precedence than if-else.

A simpler example also illustrates this:

>>> lambda x: 0 if False else True
<function <lambda> at 0x7efdbe55abf8>
>>> lambda x: (0 if False else True)
<function <lambda> at 0x7efdbe55ac80>
>>> (lambda x: 0) if False else True
True
Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
4
d = {k: (lambda x : x.sum()) if 'a' in k else 'yes' for k in ['bac','sss','asa']}

should work. The reason (as far as I understand) is that boundaries for parsing lambda is overlapping with your comprehension — basically, python parsing your lambda as x.sum() if 'a' in k else 'yes' — with reference to locals

Slam
  • 8,112
  • 1
  • 36
  • 44