Using Python Lambda - Things Need to Notice

Perceived as very Pythonic, lambdas are one of the favorite features in Python programming. So much so, that many Python programmers are tempted to use them whenever possible.

Certainly, lambdas have the advantage of making our code concise, but their overuse in our projects can lead to misuses that reduce our code’s readability and maintainability.

Before we start to explore what these misuses are, let’s first quickly review what lambdas are. If you know them pretty well, you can skip to the next section.

Lambdas, also known as lambda functions, are anonymous functions that take any number of arguments, while only having a single expression. Their declarations are signaled by the lambda keyword. The basic syntax is below.

lambda arguments: expression

Lambdas are best suitable for places where small functions are needed and they are used just one time. One common usage of lambdas is to set it as the key argument in the built-in sorted() function. Here’s an example.

>>> students = [('Mike', 'M', 15), ('Mary', 'F', 14), ('David', 'M', 16)]
>>> sorted(students, key=lambda x: x[2])
[('Mary', 'F', 14), ('Mike', 'M', 15), ('David', 'M', 16)]
# The students are sorted by age

Many tutorials have done a good job explaining what lambdas are and where lambdas can be used, and thus, there are no good reasons to repeat them extensively here.

Instead, the purpose of this article isto show you the most common misuses of lambdas so that when you use them in other scenarios other than those listed below, you’re probably using them properly.

1. Reinvent the Wheel

The first misuse of lambdas is ignoring the existing built-in functions.

Let’s still use the sorted() function as an example. Suppose that we have a list of strings, and we want to sort them using their length.

Certainly, the lambda function lambda x: len(x) works, but how about just using the built-in len() function directly?

>>> pets = ['dog', 'turtle', 'bird', 'fish', 'kitty']
>>> sorted(pets, key=lambda x: len(x))
['dog', 'bird', 'fish', 'kitty', 'turtle']
# The built-in len() function
>>> sorted(pets, key=len)
['dog', 'bird', 'fish', 'kitty', 'turtle']

Here’s another example involving the use of the max() function instead.

>>> number_tuples = [(4, 5, 7), (3, 1, 2), (9, 4, 1)]
>>> sorted(number_tuples, key=lambda x: max(x))
[(3, 1, 2), (4, 5, 7), (9, 4, 1)]
# The built-in max() function
>>> sorted(number_tuples, key=max)
[(3, 1, 2), (4, 5, 7), (9, 4, 1)]

Best practice #1: Think about built-in functions first before writing your own lambdas.

2. Assign It to a Variable

I have seen the assignment of lambdas to variables in some tutorials, including some of mine, but it is mostly intended to show beginners that lambdas essentially are functions.

However, some beginners may have taken it as good practice and think that lambdas are just a convenient way to declare a short function. The following code snippet shows you this misuse.

>>> divide_two_numbers = lambda x, y: x / y
>>> divide_two_numbers(4, 5)

Why should this be avoided? If you recall what’s mentioned above, lambdas are supposed to be used for just once and thus there is no reason to assign a lambda to a variable.

If we do need to use the related functionality, we should use the def keyword to declare a regular function like below.

If you think that it’s not cool to have two lines of code for this simple function, we can rewrite it in one line: def divide_two_numbers_fun(x,y): return x / y, which works the same way.

>>> def divide_two_numbers_fun(x,y): 
...     return x / y
>>> divide_two_numbers_fun(7, 8)

The major reason for avoiding assigning a lambda to a variable is for debugging/maintainability purposes, especially in a production/teamwork environment.

Let’s see what can potentially happen using a simplified example. In a real situation, things can go a lot more complex.

>>> divide_two_numbers(3, 0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
ZeroDivisionError: division by zero
>>> divide_two_numbers_fun(3, 0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in divide_two_numbers_fun
ZeroDivisionError: division by zero

As you can see above, with the declaration of the regular function, we know exactly which function has caused the error. By contrast, using the lambdas, it only tells us that there is a lambda causing the error.

Why is no function name shown?

It’s because lambdas are anonymous functions, all of which share the same name — . Can you imagine how frustrating it can be if your co-workers find that tens of s have errors?

Best practice #2:Write a regular function instead of a lambda when the function is to be used multiple times.

3. Improper Overuse With Higher-Order Functions

When we say higher-order functions, we mean functions that operate on other functions either by taking functions as arguments or by returning functions.

Relevant functions to the current topic are map(), filter(), and reduce(), all of which have been used more or less in many tutorials on lambdas. But this has led to a certain misuse of lambdas together with higher-order functions.

For demonstration purposes, I’ll just use the map() function in this tutorial, but the same philosophy applies to other higher-order functions too.

Suppose that we have a list of integers and we want to have a list that consists of their squares. Using a lambda with the map() function will be like below.

We’ll get an iterator — the map object from the map() function, and then, to convert it to a list, we need to call the list() function on this iterator.

>>> numbers = [1, 2, 3, 5, 8]
>>> squares = list(map(lambda x: x * x, numbers))
>>> squares
[1, 4, 9, 25, 64]

Actually, the same functionality can be achieved conveniently with list comprehensions — no higher-order functions or lambdas needed. Much more concise and readable, isn’t it?

>>> numbers = [1, 2, 3, 5, 8]
>>> squares = [x * x for x in numbers]
>>> squares
[1, 4, 9, 25, 64]

Best practice #3: Consider replacing higher-order functions using lambdas with list comprehensions.

4. Expression Is Too Cumbersome

This is less common than the previous ones. But some programmers are just trying their best to write the most Pythonic code by using lambdas whenever possible. It sometimes has a cost — readability.

Suppose that we have a list of strings and we need to sort them using a weird requirement: the number of distinct vowels in the word. Using a lambda in the sorted() function will look like below.

>>> texts = ['iiiii', 'bag', 'beto', 'blackboard', 'sequoia']
>>> sorted(texts, key=lambda x: len(set([l for l in list(x) if l in ['a','e','i','o','u']])))
['iiiii', 'bag', 'beto', 'blackboard', 'sequoia']

It works as expected, but it’s definitely not the most readable code. How about the code below?

>>> texts = ['iiiii', 'bag', 'beto', 'blackboard', 'sequoia']
>>> def number_distinct_vowels(x):
...     vowels = ['a', 'e', 'i', 'o', 'u']
...     vowels_only = [l for l in list(x) if l in vowels]
...     distinct_vowels = set(all_vowels)
...     return len(distinct_vowels)
>>> sorted(texts, key=number_distinct_vowels)
['iiiii', 'bag', 'beto', 'blackboard', 'sequoia']

Certainly, we need to write a few more lines of code but doesn’t the new code have better readability?

Best practice #4: Write a regular function if the expression of a lambda is too cumbersome.


Lambdas have always been one of the hard topics for Python beginners, and they avoid using them at all costs initially.

After a while, when their fear is gone, they start to learn lambdas and find out that they’re not really hard at all. They then start to use lambdas, but unfortunately, some may use them way too much, leading to various misuses as discussed above.

I hope that this article can help address some of these issues.

By avoiding these misuses and following the best practice tips, I bet that your Python code with correct usage of lambdas will have better readability and maintainability.

Thank you for reading!

#python #Python Lambdas #tutorial

Using Python Lambda - Things Need to Notice
31.45 GEEK