593
594 if 'aggregated_values' in lookup_data:
595 model_values = list(filter(
596 lambda x: getattr(x['instance'], lookup_data['source_column'], None) in values, 597 lookup_data['aggregated_values']
598 ))
599 item_result['aggregated'] = model_values[0]['value'] if len(model_values) else 0
593
594 if 'aggregated_values' in lookup_data:
595 model_values = list(filter(
596 lambda x: getattr(x['instance'], lookup_data['source_column'], None) in values, 597 lookup_data['aggregated_values']
598 ))
599 item_result['aggregated'] = model_values[0]['value'] if len(model_values) else 0
588 if 'related' in lookup_data:
589 item_result['related'] = self.filter_lookup_models(
590 lookup_data['related'],
591 lambda x: getattr(x, lookup_data['related_column'], None) in values 592 )
593
594 if 'aggregated_values' in lookup_data:
588 if 'related' in lookup_data:
589 item_result['related'] = self.filter_lookup_models(
590 lookup_data['related'],
591 lambda x: getattr(x, lookup_data['related_column'], None) in values 592 )
593
594 if 'aggregated_values' in lookup_data:
533 lookup_result['return_list'] = lookup_data.get('returnList', False)
534 lookup_result['Model'] = Model
535 lookup_result['mapper'] = mapper
536 lookup_result['model_values'] = list(map(lambda x: {'instance': x, 'value': getattr(x, column.name)}, models)) 537 lookup_result['source_column'] = column.name
538
539 if 'relation' in lookup_data:
A variable used in a closure is defined in a loop. This will result in all closures using the same value for the closed-over variable, which can pave way for a hideous bug.
Consider the following code snippet:
# Motivation: Create 3 functions that return `x**2`, `x**3`, and `x**4`.
# Note: This will be using the loop variable to show the bug.
powers = [lambda x: x**i for i in range(2,5)]
So, powers
is supposed to contain 3 functions to return 2nd, 3rd and 4th powers of a given number.
On execution, these are the results:
In [1]: powers = [lambda x: x**i for i in range(2,5)]
In [2]: powers[0](2) # Expected result: 4 (2**2)
Out[2]: 16
In [3]: powers[1](2) # Expected result: 8 (2**3)
Out[3]: 16
In [4]: powers[2](2) # Expected result: 16 (2**4)
Out[4]: 16
This happens because i is not local to the lambdas, but is defined in the outer scope, and it is accessed when the lambda is called — not when it is defined. At the end of the loop, the value of i is 4, so all the functions now return x**4.
In order to avoid this, you need to save the values in variables local to the lambdas, so that they don’t rely on the value of the global i
:
In [1]: powers = [lambda x, n =i: x**n for i in range(2,5)]
In [2]: powers[0](2)
Out[2]: 4
In [3]: powers[1](2)
Out[3]: 8
In [4]: powers[2](2)
Out[4]: 16