5

I have a dictionary of properties and their limiting values. For properties containing 'max', the limiting values is the maximum allowed. Similarly for minima.

I'm trying to create a dictionary of functions. Each function will check an input value against the limiting value for a property of the list.

limits = {'variable1 max': 100,
          'variable1 min': 10}

check_acceptable = {key: (lambda x: x < lim) if 'max' in key else 
                         (lambda x: x > lim) 
                    for key, lim in limits.items()}

# Now, I'd expect this to be True, since 90 < 100:
check_acceptable['variable1 max'](90)

Out: False

What happended here is that the lambda function got assigned the variable lim, and in the for loop, lim last value was 10, then my first lambda function is wrong.

How do I fix that?

--- edit - adding a more generic example of the same behaviour:

funcs = []
for i in range(5):
    funcs.append(lambda _: i)

for j in range(5):
    print(funcs[j](j), end='')

# Expected: 01234
Out: 44444
0

2 Answers 2

3

The issue - The variable lim is not "stored" in the lambda, so both lambdas compare the argument with 10.

Possible solution:

import functools
def a_less_than_b(a,b):
  return a < b

def a_greater_than_b(a,b):
  return a > b

limits = {'variable1 max': 100,
          'variable1 min': 10}

check_acceptable = {key: functools.partial(a_less_than_b, b=lim) if 'max' in key else 
                         functools.partial(a_greater_than_b, b=lim)
                    for key, lim in limits.items()}

# Now, I'd expect this to be True, since 90 < 100:
check_acceptable['variable1 max'](90)
Sign up to request clarification or add additional context in comments.

Comments

3

The problem is that each lambda inside the dict comprehension is capturing only the last version of lim it finds, as per this post. We can get around this limitation by doing some currying on the lim parameter:

limits = {'variable1 max': 100,
          'variable1 min': 10}

check_acceptable = {key: (lambda lim: (lambda x: x < lim))(lim) if 'max' in key else
                         (lambda lim: (lambda x: x > lim))(lim)
                    for key, lim in limits.items()}

The above will allow each lambda to capture each one of the arguments it encounters; it works as expected:

check_acceptable['variable1 max'](90)
=> True

1 Comment

@Raf To pretty it up, use named functions instead of lambdas. This has the added benefit of being able to debug the code more easily since it won't be all jammed on a single line.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.