AMZ DIGICOM

Digital Communication

AMZ DIGICOM

Digital Communication

Python Lambdas: Anonymous Functions in Python

PARTAGEZ

Lambda functions have been around since Python 1.0 as a means of functional programming. Their use is now largely replaced by other techniques. But there are still a few specialized applications that seasoned Python programmers should be aware of.

What are lambda functions in Python?

In Python, a “lambda function” is an anonymous function. To create this lambda function, the keyword “lambda” should be used. This expression thus consists of the keyword “lambda”, followed by a list of arguments, a colon, and a separate expression (“expression”). When the lambda function is called, the expression is completed with the arguments and evaluated:

lambda argument: expression

Functions are a fundamental language element of almost all programming languages ​​and represent the smallest unit of reusable code. Usually the Python functions are defined with the “def” keyword. Here is for example the square function, which multiplies a number by itself:

# Définir la fonction carré
def square(num):
  return num * num
# Démontrer que cela fonctionne
assert square(9) == 81

python

Besides the well-known method of defining functions in Python using the “def” keyword, this language also uses “lambdas”. It is short, anonymous (unnamed) functions that define an expression using parameters. Lambdas can be used anywhere a function is expected or can be named by assignment. Here is the lambda version equivalent of the aforementioned square function:

# Créer la fonction carré
squared = lambda num: num * num
# Démontrer que cela fonctionne
assert squared(9) == 81

python

In Python, the term “lambda function” refers to a function generated using the lambda keyword. Lambda is not the name of a function, nor is it one of the Python operators.

What is the difference between lambda and def?

At first glance, it seems strange that Python, along with “lambda” and “def”, has two ways to create functions. However, “lambda” is not a function strictly speaking, but only another spelling to locally create short functions. Each function that was created with “lambda” is indeed also generated via “def”. The converse, however, is not true.

Syntactically, “lambda” and “def” are both keywords. The difference between the two, however, lies in the strict separation between a statement (“statement”) and an expression (“expression”) in Python language. To summarize, statements are steps in the execution of code while expressions are evaluated against a value.

The keyword “def” starts a statement (specifically a “compound statement”) that contains other statements. Within the “def” statement, “return” statements may appear. When calling a function defined with “def”, a “return” statement returns a value.

Unlike the “def” statement, the “lambda” keyword starts an expression that must not contain statements. The lambda expression accepts one or more arguments and returns an anonymous function. If the created lambda function is called, the contained expression is evaluated with the passed arguments and then returned.

What are the restrictions of Python lambda expressions?

Python purposefully restricts the uses of lambda functions, because in general, it is better to name the functions. This forces programmers to think about the meaning of the function and to clearly delineate the different parts.

Unlike the body of a function defined via the “def” keyword, lambdas cannot contain any statements. It is therefore cannot use “if”, “for”, etc. in a lambda function. Even throwing an exception is impossible, because the “raise” statement is required for that.

Lambda functions in Python should only contain a separate expression that will be evaluated when called. In the lambda expression, no type annotation can be used. Now, other techniques are employed in the majority of use cases for lambda functions in the Python language. We can here in particular cite lists in comprehension.

Why are lambda functions used in Python?

Generally, lambdas fall under functional programming. In some languages, like JavaScript, anonymous functions are often used without a specific keyword being used. In Python, lambda expressions are used to locally generate small functions without all the accompanying stuff. We show you the most useful use cases.

Insert lambdas into higher order functions in Python

Lambdas are often used in combination with higher order functions such as “map()”, “filter()” and “reduce()”. Thanks to them, the elements of an “iterable” object can be transformed without using a loop. Higher order functions are defined as functions that accept other functions as parameters or return a function.

The “map()” function accepts a function and an iterable as parameters and executes the function for each element of the iterable object. Let’s look at the problem of generating square numbers: we use the “map()” function and let’s pass a lambda expression as argument, which generates the square function. With “map()”, the square function is applied to all elements of the list:

nums = [3, 5, 7]
# Nombres carrés à l’aide de « map() » et « lambda »
squares = map(lambda num: num ** 2, nums)
# Démontrer que cela fonctionne
assert list(squares) == [9, 25, 49]

python

Since Python 3.0, the “map()” and “filter()” functions return an iterable instead of a list. In the “assert” statement, we use a “list()” call to extract the iterable into a list.

Thanks to list comprehensions, there is now a more modern and preferred approach to dealing with iterables. Instead of using “map()” and generating a lambda function, we describe the operation directly:

nums = [3, 5, 7]
# Nombres carrés à l’aide de la liste en compréhension
squares = [num ** 2 for num in nums]
# Démontrer que cela fonctionne
assert squares == [9, 25, 49]

python

Thanks to the “filter()” function, you can filter the elements of an iterable. We expand our example so that only precise square numbers are generated:

# Liste de chiffres de 1 à 4
nums = [1, 2, 3, 4]
# Carré de chaque chiffre
squares = list(map(lambda num: num ** 2, nums))
# Filtrer les carrés pairs
even_squares = filter(lambda square: square % 2 == 0, squares)
# Démontrer que cela fonctionne
assert list(even_squares) == [4, 16]

python

We again present the preferred modern approach, using a list comprehension, to generate the same result without resorting to lambdas or higher order functions. So we use the “if” part of the comprehension to filter out the even elements of the resulting square digits:

# Liste de chiffres de 1 à 4 au carré
squares = [num ** 2 for num in range(1, 5)]
# Filtrer les carrés pairs
even_squares = [square for square in squares if square % 2 == 0]
# Démontrer que cela fonctionne
assert even_squares == [4, 16]

python

Python’s “reduce()” function is no longer part of the standard library since Python 3.0. It has been moved to the “functools” module.

Realize key functions in Python, like lambdas

Comprehensions have largely replaced the use of the classic higher-order functions “map()” and “filter()”. Thanks to the “key functions”, however, there is a application scenario in which the strengths of lambdas are fully exploited.

The Python comparison functions “sorted()”, “min()” and “max()” work on the basis of iterables. During the call, each element of the iterable is subjected to a comparison. Each of the three functions accepts a key function as an optional “key” parameter. The key function is called for each item and returns a key value for comparison.

Consider the following problem as an example. We have a folder containing image files whose names are reproduced in a Python list. We want to sort this list. The file names all start with “img” and are followed by a number:

# Liste des noms des fichiers image
images = ['img1', 'img2', 'img30', 'img3', 'img22', 'img100']

python

If we use Python’s “sorted()” function, “lexicographical order” is used. This means that sequential digits are treated as single digits. Thus, the numbers [‘1’, ‘2’, ‘100’] » are presented in the order « [‘1’, ‘100’, ‘2’] “. The result does not correspond to our expectations:

# Trier selon l’ordre lexicographique
sorted_image = sorted(images)
# Démontrer que cela fonctionne
assert sorted_image == ['img1', 'img100', 'img2', 'img22', 'img3', 'img30']

python

In order to configure the sorting according to our wishes, we transmit a “lambda” expression that generates a key function. The key function extracts the numeric part of a filename, which will then be used as the key by the “sorted()” function:

# Extraire le composant numérique et trier en tant qu’entiers
sorted_image = sorted(images, key=lambda name: int(name[3:]))
# Démontrer que cela fonctionne
assert sorted_image == ['img1', 'img2', 'img3', 'img22', 'img30', 'img100']

python

The key function is used locally only and only once. There is no need to define a named function separately. Lambdas are thus the proper way to create key functions. Let’s look at two other examples.

Besides “sorted()”, Python’s built-in functions “min()” and “max()” accept an optional key function. Functions find the smallest or largest element of a list or other iterable. What precisely constitutes the smallest or largest element is a matter of definition and is determined via the key function.

In a list of simple values, such as a list of numbers, what is meant by “smallest” or “largest” element is obvious. No special key function is required here:

nums = [42, 69, 51, 13]
assert min(nums) == 13
assert max(nums) == 69

python

If no key function is passed, the identity function “f(x) = x” is used implicitly. This function is as easy to define as the Python lambda with “lambda x:x”.

What then happens when the elements of an iterable contain several data points respectively? Imagine a list of dictionaries that represent people, with their name and age. According to what criteria Should ‘min()’ and ‘max()’ determine which elements are smallest or largest ? This is where the key function comes into play.

To illustrate the how key functions work, we need sample data. We create a “Person()” function serving as a constructor:

# Fonction de constructeur pour le dictionnaire représentant une personne
def Person(name, age):
  return {'name': name, 'age': age}
# Vérifier que cela fonctionne tel que prévu
assert Person('Jim', 42) == {'name': 'Jim', 'age': 42}

python

Thanks to our constructor function, we create a list of people :

# Créer un liste de personnes
people = [Person('Jim', 42), Person('Jack', 51), Person('John', 69)]

python

Finally, we find the oldest person via the “max()” call. We thus create, via a lambda expression, a key functionwhich accepts a dictionary of people and extracts the age as a comparison element:

# Trouver la personne la plus âgée
oldest = max(people, key=lambda person: person['age'])
# Vérifier que cela fonctionne
assert oldest == Person('John', 69)

python

The approach works the same way for the “min()” function. Here we define the key function outside of the “min()” call ‘, but we use the lambda expression again. This improves readability and is advantageous when the key function is used locally many times:

# Définir la fonction de clé pour comparer les personnes selon leur âge
by_age = lambda person: person['age']
# Trouver la personne la plus jeune
youngest = min(people, key=by_age)
# Vérifier que cela fonctionne
assert youngest == Person('Jim', 42)

python

Creating closures with Python lambdas

Python lambdas are also used in the definition of closures.. These are functions that are created from other functions and store a value for this purpose. Closures are used, for example, to create families of similar functions. Here is a common example explaining the creation of power functions.

Power functions take an argument and raise it to the corresponding power. Known examples are the square function “f(x) = x^2” and the cube function “f(x) = x^3”. A constructor function allows arbitrary power functions to be created as closures. We use a lambda expression and thus avoid defining an internal named function:

# Définir la fonction de constructeur pour les fonctions de puissance
def power(n):
  return lambda num: num ** n

# Créer les fonctions carré et cube comme fermetures
square = power(2)
cubic = power(3)

# Démontrer que cela fonctionne
assert square(10) == 100
assert cubic(10) == 1000

python

Immediately Invoked Function Expression (IIFE) with Python Lambdas

IIFEs (for Immediately Invoked Function Expression; pronounced “ayfi”) are a known pattern in JavaScript. An anonymous function is thus defined and immediately executed.

When this turns out to be of little use even with the limitation in Python, lambdas can be used as IIFE. We only need parentheses around the lambda expression:

(lambda num: num * num)

python

As well as another pair of parentheses surrounding the argument(s):

assert (lambda num: num * num)(3) == 9

python

Télécharger notre livre blanc

Comment construire une stratégie de marketing digital ?

Le guide indispensable pour promouvoir votre marque en ligne

En savoir plus

Souhaitez vous Booster votre Business?

écrivez-nous et restez en contact