How to Use Python Lambda Functions

How to Use Python Lambda Functions

How to Use Python Lambda Functions.In Python, a Lambda Function refers to a small, anonymous function. We call the functions anonymous because technically it has no name — we don’t define it with the standard `def` keyword that we normally use in Python

In Python, a Lambda Function refers to a small, anonymous function. We call the functions anonymous because technically it has no name — we don’t define it with the standard def keyword that we normally use in Python. Instead, Lambda Functions are defined as one-liners that execute a single expression.

Although they look different, Lambda Functions behave in the same way as regular functions that are declared using the def keyword. They are executed in a similar way as regular Python functions, with the exception that they strictly execute a single expression.

Lambda functions are mainly used for creating small, single-use functions. You’ll often see them in-place of what might otherwise be a fully defined function, but written as a Lambda to save time and space. From the Python Design and History FAQ:

Unlike lambda forms in other languages, where they add functionality, Python lambdas are only a shorthand notation if you’re too lazy to define a function.

For a concrete description, Lambda functions can be understood through the following 3 points:

  • A Lambda Function must always execute a single expression
  • An expression is a Python code run by the lambda function, which may or may not return any value
  • A lambda function can take any number of input arguments and return any number of output arguments, as long as the function is maintained as a single expression

Basic Lambda Functions in Python

All Python Lambda Functions following the same exact syntax:

lambda arguments: expression

For example, let's say we want to declare a Lambda Function that computes the remainder of a division operation. Of course, we could do this without a function with Python’s % operator, but it’s not very readable when going through the code. It’s easy to miss and not intuitive to catch when reading through for the first time.

When we use a Lambda Function however, we’re able to clean things up for better readability and cleaner code:

compute_remainder = lambda x, y: x % y

Our Lambda Function takes on 2 arguments, x and y, and then computes the remainder of those 2 using Python’s % operator via x % y. To call the function, all we have to do is apply it like any other regular Python function by passing the arguments and saving the return value in a variable.

### Prints out 1
r = compute_remainder(10, 3)
print(r)

Our code using the Lambda Function is simple and contained.

The filter() Function

The filter() function is used to select specific elements from a Python sequence. A Python sequence is a data type that can hold multiple elements such as a list, tuple, set, or string.

The filter function will take two items as an input, an object and a sequence:

filter(object, sequence)

The object will be our Python Lambda Function. Thus, we are filtering the sequence using our Python Lambda function.

Since the Lambda Function we are passing will be performing a filtering operation, we’ll need it to strictly return a single boolean value — True to keep an element and False to filter it out. The filter function will then return another sequence only containing the elements that evaluated to True by the Lambda.

For example, let’s say we have a list of numbers in which we want to filter out all numbers which are less than 50. We can do this with list comprehension:

### Prints out [66, 91, 98, 80, 99]
data = [66, 15, 91, 30, 35, 38, 43, 20, 38, 28, 98, 50, 7, 80, 99]
filtered = [d for d in data if d > 50]
print(filtered)

While list comprehension is definitely Pythonic, it’s not very reader-friendly. Instead, the filter function with a Lambda will look a lot cleaner.

### Prints out [66, 91, 98, 80, 99]
data = [66, 15, 91, 30, 35, 38, 43, 20, 38, 28, 98, 50, 7, 80, 99]
filtered = list(filter(lambda x: (x > 50), data))
print(filtered)

Our filter fits nicely into a one-liner while being more readable than list comprehension and accomplishing the same task.

The map() Function

The map() function is used to apply an operator or expression to every element in a sequence. For example, if your sequence is a list of numbers, you might want to divide each number by 2, which is a great situation to use the map() function.

The map function will take two items as an input, an object and a sequence:

map(object, sequence)

Just like before, the object will be our Python Lambda Function. Thus, we are executing the expression in our Lambda to each element in the sequence.

Since the Lambda Function we are passing will be executing an expression on each list element, our Lambda can return any type of value. The only thing to really keep an eye out for is that your list doesn’t have any elements that would throw an error at your Lambda function. For example, you might have a list that contains both integers and strings, so attempting to divide each element by 2 wouldn’t work.

Let’s use a similar example to the one we used with filter() we had a list of numbers. In this case, we’re going to write code to square each element in the list. Again, we can always do this with list comprehension:

### Prints out [33.0, 7.5, 45.5, 15.0, 17.5, 19.0, 21.5, 10.0, 19.0, ### 14.0, 49.0, 25.0, 3.5, 40.0, 49.5]
data = [66, 15, 91, 30, 35, 38, 43, 20, 38, 28, 98, 50, 7, 80, 99]
mapped = [(x / 2) for x in data]
print(mapped)

While list comprehension is definitely Pythonic, it’s not very reader-friendly. Instead, the map function with a Lambda will look a lot cleaner.

### Prints out [33.0, 7.5, 45.5, 15.0, 17.5, 19.0, 21.5, 10.0, 19.0, ### 14.0, 49.0, 25.0, 3.5, 40.0, 49.5]
data = [66, 15, 91, 30, 35, 38, 43, 20, 38, 28, 98, 50, 7, 80, 99]
mapped = list(map(lambda x: (x / 2), data))
print(mapped)

Our mapping fits nicely into a one-liner while being more readable than list comprehension and accomplishing the same task.

Conclusion

So there you have it! Your practical introduction to Python Lambda Functions.

If you’re hungry for more, not to worry! There’s a whole lot more to learn about the many intricacies of Python. As recommended reading, the Real Python is a great resource with many in-depth tutorials. If you want to learn more about Python in general, Coursera has a Python for Everybody course that’s more application focused.

A Practical Introduction to Python Lambda Functions

A Practical Introduction to Python Lambda Functions

A Practical Introduction to Python Lambda Functions: In Python, a Lambda Function refers to a small, anonymous function.

In Python, a Lambda Function refers to a small, anonymous function. We call the functions anonymous because technically it has no name — we don’t define it with the standard def keyword that we normally use in Python. Instead, Lambda Functions are defined as one-liners that execute a single expression.

Although they look different, Lambda Functions behave in the same way as regular functions that are declared using the def keyword. They are executed in a similar way as regular Python functions, with the exception that they strictly execute a single expression.

Lambda functions are mainly used for creating small, single-use functions. You’ll often see them in-place of what might otherwise be a fully defined function, but written as a Lambda to save time and space. From the Python Design and History FAQ:

Unlike lambda forms in other languages, where they add functionality, Python lambdas are only a shorthand notation if you’re too lazy to define a function.

For a concrete description, Lambda functions can be understood through the following 3 points:

  • A Lambda Function must always execute a single expression
  • An expression is a Python code run by the lambda function, which may or may not return any value
  • A lambda function can take any number of input arguments and return any number of output arguments, as long as the function is maintained as a single expression
Basic Lambda Functions in Python

All Python Lambda Functions following the same exact syntax:

lambda arguments: expression

For example, let's say we want to declare a Lambda Function that computes the remainder of a division operation. Of course, we could do this without a function with Python’s % operator, but it’s not very readable when going through the code. It’s easy to miss and not intuitive to catch when reading through for the first time.

When we use a Lambda Function however, we’re able to clean things up for better readability and cleaner code:

compute_remainder = lambda x, y: x % y

Our Lambda Function takes on 2 arguments, x and y, and then computes the remainder of those 2 using Python’s % operator via x % y. To call the function, all we have to do is apply it like any other regular Python function by passing the arguments and saving the return value in a variable.

### Prints out 1
r = compute_remainder(10, 3)
print(r)

Our code using the Lambda Function is simple and contained.

The filter() Function

The filter() function is used to select specific elements from a Python sequence. A Python sequence is a data type that can hold multiple elements such as a list, tuple, set, or string.

The filter function will take two items as an input, an object and a sequence:

filter(object, sequence)

The object will be our Python Lambda Function. Thus, we are filtering the sequence using our Python Lambda function.

Since the Lambda Function we are passing will be performing a filtering operation, we’ll need it to strictly return a single boolean value — True to keep an element and False to filter it out. The filter function will then return another sequence only containing the elements that evaluated to True by the Lambda.

For example, let’s say we have a list of numbers in which we want to filter out all numbers which are less than 50. We can do this with list comprehension:

### Prints out [66, 91, 98, 80, 99]
data = [66, 15, 91, 30, 35, 38, 43, 20, 38, 28, 98, 50, 7, 80, 99]
filtered = [d for d in data if d > 50]
print(filtered)

While list comprehension is definitely Pythonic, it’s not very reader-friendly. Instead, the filter function with a Lambda will look a lot cleaner.

### Prints out [66, 91, 98, 80, 99]
data = [66, 15, 91, 30, 35, 38, 43, 20, 38, 28, 98, 50, 7, 80, 99]
filtered = list(filter(lambda x: (x > 50), data))
print(filtered)

Our filter fits nicely into a one-liner while being more readable than list comprehension and accomplishing the same task.

The map() Function

The map() function is used to apply an operator or expression to every element in a sequence. For example, if your sequence is a list of numbers, you might want to divide each number by 2, which is a great situation to use the map() function.

The map function will take two items as an input, an object and a sequence:

map(object, sequence)

Just like before, the object will be our Python Lambda Function. Thus, we are executing the expression in our Lambda to each element in the sequence.

Since the Lambda Function we are passing will be executing an expression on each list element, our Lambda can return any type of value. The only thing to really keep an eye out for is that your list doesn’t have any elements that would throw an error at your Lambda function. For example, you might have a list that contains both integers and strings, so attempting to divide each element by 2 wouldn’t work.

Let’s use a similar example to the one we used with filter() we had a list of numbers. In this case, we’re going to write code to square each element in the list. Again, we can always do this with list comprehension:

### Prints out [33.0, 7.5, 45.5, 15.0, 17.5, 19.0, 21.5, 10.0, 19.0, ### 14.0, 49.0, 25.0, 3.5, 40.0, 49.5]
data = [66, 15, 91, 30, 35, 38, 43, 20, 38, 28, 98, 50, 7, 80, 99]
mapped = [(x / 2) for x in data]
print(mapped)

While list comprehension is definitely Pythonic, it’s not very reader-friendly. Instead, the map function with a Lambda will look a lot cleaner.

### Prints out [33.0, 7.5, 45.5, 15.0, 17.5, 19.0, 21.5, 10.0, 19.0, ### 14.0, 49.0, 25.0, 3.5, 40.0, 49.5]
data = [66, 15, 91, 30, 35, 38, 43, 20, 38, 28, 98, 50, 7, 80, 99]
mapped = list(map(lambda x: (x / 2), data))
print(mapped)

Our mapping fits nicely into a one-liner while being more readable than list comprehension and accomplishing the same task.

Conclusion

So there you have it! Your practical introduction to Python Lambda Functions.

How to Use Python lambda Functions

How to Use Python lambda Functions

In this tutorial, you'll learn about Python lambda functions. You'll see how they compare with regular functions and how you can use Python lambda Functions

Originally published by Andre Burgaud at https://realpython.com

Python and other languages like Java, C#, and even C++ have had lambda functions added to their syntax, whereas languages like LISP or the ML family of languages, Haskell, OCaml, and F#, use lambdas as a core concept.

Python lambdas are little, anonymous functions, subject to a more restrictive but more concise syntax than regular Python functions.

By the end of this article, you’ll know:

  • How Python lambdas came to be
  • How lambdas compare with regular function objects
  • How to write lambda functions
  • Which functions in the Python standard library leverage lambdas
  • When to use or avoid Python lambda functions

This tutorial is mainly for intermediate to experienced Python programmers, but it is accessible to any curious minds with interest in programming and lambda calculus.

All the examples included in this tutorial have been tested with Python 3.7.

Table of Contents

  • Lambda Calculus
  • History
  • First Example
  • Anonymous Functions
  • Python Lambda and Regular Functions
  • Functions
  • Traceback
  • Syntax
  • Arguments
  • Decorators
  • Closure
  • Evaluation Time
  • Testing Lambdas
  • Lambda Expression Abuses
  • Raising an Exception
  • Cryptic Style
  • Python Classes
  • Appropriate Uses of Lambda Expressions
  • Classic Functional Constructs
  • Key Functions
  • UI Frameworks
  • Python Interpreter
  • timeit
  • Monkey Patching
  • Alternatives to Lambdas
  • Map
  • Filter
  • Reduce
  • Are Lambdas Pythonic or Not?
  • Conclusion
Lambda Calculus

Lambda expressions in Python and other programming languages have their roots in lambda calculus, a model of computation invented by Alonzo Church. You’ll uncover when lambda calculus was introduced and why it’s a fundamental concept that ended up in the Python ecosystem.

History

Alonzo Church formalized lambda calculus, a language based on pure abstraction, in the 1930s. Lambda functions are also referred to as lambda abstractions, a direct reference to the abstraction model of Alonzo Church’s original creation.

Lambda calculus can encode any computation. It is Turing complete, but contrary to the concept of a Turing machine, it is pure and does not keep any state.

Functional languages get their origin in mathematical logic and lambda calculus, while imperative programming languages embrace the state-based model of computation invented by Alan Turing. The two models of computation, lambda calculus and Turing machines, can be translated into each another. This equivalence is known as the Church-Turing hypothesis.

Functional languages directly inherit the lambda calculus philosophy, adopting a declarative approach of programming that emphasizes abstraction, data transformation, composition, and purity (no state and no side effects). Examples of functional languages include Haskell, Lisp, or Erlang.

By contrast, the Turing Machine led to imperative programming found in languages like Fortran, C, or Python.

The imperative style consists of programming with statements, driving the flow of the program step by step with detailed instructions. This approach promotes mutation and requires managing state.

The separation in both families presents some nuances, as some functional languages incorporate imperative features, like OCaml, while functional features have been permeating the imperative family of languages in particular with the introduction of lambda functions in Java, or Python.

Python is not inherently a functional language, but it adopted some functional concepts early on. In January 1994, map(), filter(), reduce(), and the lambda operator were added to the language.

First Example

Here are a few examples to give you an appetite for some Python code, functional style.

The identity function, a function that returns its argument, is expressed with a standard Python function definition using the keyword def as follows:

>>> def identity(x):
...     return x

identity() takes an argument x and returns it upon invocation.

In contrast, if you use a Python lambda construction, you get the following:

>>> lambda x: x

In the example above, the expression is composed of:

  • The keyword: lambda
  • A bound variable: x
  • A body: x

Note: In the context of this article, a bound variable is an argument to a lambda function.

In contrast, a free variable is not bound and may be referenced in the body of the expression. A free variable can be a constant or a variable defined in the enclosing scope of the function.

You can write a slightly more elaborated example, a function that adds 1 to an argument, as follows:

>>> lambda x: x + 1

You can apply the function above to an argument by surrounding the function and its argument with parentheses:

>>> (lambda x: x + 1)(2)
3

Reduction is a lambda calculus strategy to compute the value of the expression. It consists of substituting the argument 2 for x:

(lambda x: x + 1)(2) = lambda 2: 2 + 1
                     = 2 + 1
                     = 3

Because a lambda function is an expression, it can be named. Therefore you could write the previous code as follows:

>>> add_one = lambda x: x + 1
>>> add_one(2)
3

The above lambda function is equivalent to writing this:

def add_one(x):
    return x + 1

These functions all take a single argument. You may have noticed that, in the definition of the lambdas, the arguments don’t have parentheses around them. Multi-argument functions (functions that take more than one argument) are expressed in Python lambdas by listing arguments and separating them with a comma (,) but without surrounding them with parentheses:

>>> full_name = lambda first, last: f'Full name: {first.title()} {last.title()}'
>>> full_name('guido', 'van rossum')
'Full name: Guido Van Rossum'

The lambda function assigned to full_name takes two arguments and returns a string interpolating the two parameters first and last. As expected, the definition of the lambda lists the arguments with no parentheses, whereas calling the function is done exactly like a normal Python function, with parentheses surrounding the arguments.

Anonymous Functions

The following terms may be used interchangeably depending on the programming language type and culture:

  • Anonymous functions
  • Lambda functions
  • Lambda expressions
  • Lambda abstractions
  • Lambda form
  • Function literals

For the rest of this article after this section, you’ll mostly see the term lambda function.

Taken literally, an anonymous function is a function without a name. In Python, an anonymous function is created with the lambda keyword. More loosely, it may or not be assigned a name. Consider a two-argument anonymous function defined with lambda but not bound to a variable. The lambda is not given a name:

>>> lambda x, y: x + y

The function above defines a lambda expression that takes two arguments and returns their sum.

Other than providing you with the feedback that Python is perfectly fine with this form, it doesn’t lead to any practical use. You could invoke the function in the Python interpreter:

>>> _(1, 2)
3

The example above is taking advantage of the interactive interpreter-only feature provided via the underscore (_). See the note below for more details.

You could not write similar code in a Python module. Consider the _ in the interpreter as a side effect that you took advantage of. In a Python module, you would assign a name to the lambda, or you would pass the lambda to a function. You’ll use those two approaches later in this article.

Note: In the interactive interpreter, the single underscore (_) is bound to the last expression evaluated.

In the example above, the _ points to the lambda function. For more details about the usage of this special character in Python, check out The Meaning of Underscores in Python.

Another pattern used in other languages like JavaScript is to immediately execute a Python lambda function. This is known as an Immediately Invoked Function Expression (IIFE, pronounce “iffy”). Here’s an example:

>>> (lambda x, y: x + y)(2, 3)
5

The lambda function above is defined and then immediately called with two arguments (2 and 3). It returns the value 5, which is the sum of the arguments.

Several examples in this tutorial use this format to highlight the anonymous aspect of a lambda function and avoid focusing on lambda in Python as a shorter way of defining a function.

Python does not encourage using immediately invoked lambda expressions. It simply results from a lambda expression being callable, unlike the body of a normal function.

Lambda functions are frequently used with higher-order functions, which take one or more functions as arguments or return one or more functions.

A lambda function can be a higher-order function by taking a function (normal or lambda) as an argument like in the following contrived example:

>>> high_ord_func = lambda x, func: x + func(x)
>>> high_ord_func(2, lambda x: x * x)
6
>>> high_ord_func(2, lambda x: x + 3)
7

Python exposes higher-order functions as built-in functions or in the standard library. Examples include map(), filter(), functools.reduce(), as well as key functions like sort(), sorted(), min(), and max().

Python Lambda and Regular Functions

This quote from the Python Design and History FAQ seems to set the tone about the overall expectation regarding the usage of lambda functions in Python:

Unlike lambda forms in other languages, where they add functionality, Python lambdas are only a shorthand notation if you’re too lazy to define a function. (Source)

Nevertheless, don’t let this statement deter you from using Python’s lambda. At first glance, you may accept that a lambda function is a function with some syntactic sugar shortening the code to define or invoke a function. The following sections highlight the commonalities and subtle differences between normal Python functions and lambda functions.

Functions

At this point, you may wonder what fundamentally distinguishes a lambda function bound to a variable from a regular function with a single return line: under the surface, almost nothing. Let’s verify how Python sees a function built with a single return statement versus a function constructed as an expression (lambda).

The dis module exposes functions to analyze Python bytecode generated by the Python compiler:

>>> import dis
>>> add = lambda x, y: x + y
>>> type(add)
<class 'function'>
>>> dis.dis(add)
  1           0 LOAD_FAST                0 (x)
              2 LOAD_FAST                1 (y)
              4 BINARY_ADD
              6 RETURN_VALUE
>>> add
<function <lambda> at 0x7f30c6ce9ea0>

You can see that dis() expose a readable version of the Python bytecode allowing the inspection of the low-level instructions that the Python interpreter will use while executing the program.

Now see it with a regular function object:

>>> import dis
>>> def add(x, y): return x + y
>>> type(add)
<class 'function'>
>>> dis.dis(add)
  1           0 LOAD_FAST                0 (x)
              2 LOAD_FAST                1 (y)
              4 BINARY_ADD
              6 RETURN_VALUE
>>> add
<function add at 0x7f30c6ce9f28>

The bytecode interpreted by Python is the same for both functions. But you may notice that the naming is different: the function name is add for a function defined with def, whereas the Python lambda function is seen as lambda.

Traceback

You saw in the previous section that, in the context of the lambda function, Python did not provide the name of the function, but only <lambda>. This can be a limitation to consider when an exception occurs, and a traceback shows only <lambda>:

>>> div_zero = lambda x: x / 0
>>> div_zero(2)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 1, in <lambda>
ZeroDivisionError: division by zero

The traceback of an exception raised while a lambda function is executed only identifies the function causing the exception as <lambda>.

Here’s the same exception raised by a normal function:

>>> def div_zero(x): return x / 0
>>> div_zero(2)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 1, in div_zero
ZeroDivisionError: division by zero

The normal function causes a similar error but results in a more precise traceback because it gives the function name, div_zero.

Syntax

As you saw in the previous sections, a lambda form presents syntactic distinctions from a normal function. In particular, a lambda function has the following characteristics:

  • It can only contain expressions and can’t include statements in its body.
  • It is written as a single line of execution.
  • It does not support type annotations.
  • It can be immediately invoked (IIFE).

No Statements

A lambda function can’t contain any statements. In a lambda function, statements like return, pass, assert, or raise will raise a SyntaxError exception. Here’s an example of adding assert to the body of a lambda:

>>> (lambda x: assert x == 2)(2)
  File "<input>", line 1
    (lambda x: assert x == 2)(2)
                    ^
SyntaxError: invalid syntax

This contrived example intended to assert that parameter x had a value of 2. But, the interpreter identifies a SyntaxError while parsing the code that involves the statement assert in the body of the lambda.

Single Expression

In contrast to a normal function, a Python lambda function is a single expression. Although, in the body of a lambda, you can spread the expression over several lines using parentheses or a multiline string, it remains a single expression:

>>> (lambda x:
... (x % 2 and 'odd' or 'even'))(3)
'odd'

The example above returns the string 'odd' when the lambda argument is odd, and 'even' when the argument is even. It spreads across two lines because it is contained in a set of parentheses, but it remains a single expression.

Type Annotations

If you’ve started adopting type hinting, which is now available in Python, then you have another good reason to prefer normal functions over Python lambda functions. In a lambda function, there is no equivalent for the following:

def full_name(first: str, last: str) -> str:
    return f'{first.title()} {last.title()}'

Any type error with full_name() can be caught by tools like mypy or pyre, whereas a SyntaxError with the equivalent lambda function is raised at runtime:

>>> lambda first: str, last: str: first.title() + " " + last.title() -> str
  File "<stdin>", line 1
    lambda first: str, last: str: first.title() + " " + last.title() -> str

SyntaxError: invalid syntax

Like trying to include a statement in a lambda, adding type annotation immediately results in a SyntaxError at runtime.

IIFE

You’ve already seen several examples of immediately invoked function execution:

>>> (lambda x: x * x)(3)
9

Outside of the Python interpreter, this feature is probably not used in practice. It’s a direct consequence of a lambda function being callable as it is defined. For example, this allows you to pass the definition of a Python lambda expression to a higher-order function like map(), filter(), or functools.reduce(), or to a key function.

Arguments

Like a normal function object defined with def, Python lambda expressions support all the different ways of passing arguments. This includes:

  • Positional arguments
  • Named arguments (sometimes called keyword arguments)
  • Variable list of arguments (often referred to as varargs)
  • Variable list of keyword arguments
  • Keyword-only arguments

The following examples illustrate options open to you in order to pass arguments to lambda expressions:

>>> (lambda x, y, z: x + y + z)(1, 2, 3)
6
>>> (lambda x, y, z=3: x + y + z)(1, 2)
6
>>> (lambda x, y, z=3: x + y + z)(1, y=2)
6
>>> (lambda *args: sum(args))(1,2,3)
6
>>> (lambda **kwargs: sum(kwargs.values()))(one=1, two=2, three=3)
6
>>> (lambda x, *, y=0, z=0: x + y + z)(1, y=2, z=3)
6

Decorators

In Python, a decorator is the implementation of a pattern that allows adding a behavior to a function or a class. It is usually expressed with the @decorator syntax prefixing a function. Here’s a contrived example:

def some_decorator(f):
def wraps(*args):
print(f"Calling function '{f.name}'")
return f(args)
return wraps

@some_decorator
def decorated_function(x):
print(f"With argument '{x}'")

In the example above, some_decorator() is a function that adds a behavior to decorated_function(), so that invoking decorated_function("Python") results in the following output:

Calling function 'decorated_function'
With argument 'Python'

decorated_function() only prints With argument 'Python', but the decorator adds an extra behavior that also prints Calling function 'decorated_function'.

A decorator can be applied to a lambda. Although it’s not possible to decorate a lambda with the @decorator syntax, a decorator is just a function, so it can call the lambda function:

# Defining a decorator
def trace(f):
def wrap(*args, **kwargs):
print(f"[TRACE] func: {f.name}, args: {args}, kwargs: {kwargs}")
return f(*args, **kwargs)
return wrap

Applying decorator to a function

@trace
def add_two(x):
return x + 2

Calling the decorated function

add_two(3)

Applying decorator to a lambda

print((trace(lambda x: x ** 2))(3))

add_two(), decorated with @trace on line 11, is invoked with argument 3 on line 15. By contrast, on line 18, a lambda function is immediately involved and embedded in a call to trace(), the decorator. When you execute the code above you obtain the following:

[TRACE] func: add_two, args: (3,), kwargs: {}
[TRACE] func: <lambda>, args: (3,), kwargs: {}
9

See how, as you’ve already seen, the name of the lambda function appears as <lambda>, whereas add_two is clearly identified for the normal function.

Decorating the lambda function this way could be useful for debugging purposes, possibly to debug the behavior of a lambda function used in the context of a higher-order function or a key function. Let’s see an example with map():

list(map(trace(lambda x: x*2), range(3)))

The first argument of map() is a lambda that multiplies its argument by 2. This lambda is decorated with trace(). When executed, the example above outputs the following:

[TRACE] Calling <lambda> with args (0,) and kwargs {}
[TRACE] Calling <lambda> with args (1,) and kwargs {}
[TRACE] Calling <lambda> with args (2,) and kwargs {}
[0, 2, 4]

The result [0, 2, 4] is a list obtained from multiplying each element of range(3). For now, consider range(3) equivalent to the list [0, 1, 2].

You will be exposed to map() in more details in Map.

A lambda can also be a decorator, but it’s not recommended. If you find yourself needing to do this, consult PEP 8, Programming Recommendations.

Closure

A closure is a function where every free variable, everything except parameters, used in that function is bound to a specific value defined in the enclosing scope of that function. In effect, closures define the environment in which they run, and so can be called from anywhere.

The concepts of lambdas and closures are not necessarily related, although lambda functions can be closures in the same way that normal functions can also be closures. Some languages have special constructs for closure or lambda (for example, Groovy with an anonymous block of code as Closure object), or a lambda expression (for example, Java Lambda expression with a limited option for closure).

Here’s a closure constructed with a normal Python function:

def outer_func(x):
y = 4
def inner_func(z):
print(f"x = {x}, y = {y}, z = {z}")
return x + y + z
return inner_func
for i in range(3):
closure = outer_func(i)
print(f"closure({i+5}) = {closure(i+5)}")

outer_func() returns inner_func(), a nested function that computes the sum of three arguments:

  • x is passed as an argument to outer_func().
  • y is a variable local to outer_func().
  • z is an argument passed to inner_func().

To test the behavior of outer_func() and inner_func(), outer_func() is invoked three times in a for loop that prints the following:

x = 0, y = 4, z = 5
closure(5) = 9
x = 1, y = 4, z = 6
closure(6) = 11
x = 2, y = 4, z = 7
closure(7) = 13

On line 9 of the code, inner_func() returned by the invocation of outer_func() is bound to the name closure. On line 5, inner_func() captures x and y because it has access to its embedding environment, such that upon invocation of the closure, it is able to operate on the two free variables x and y.

Similarly, a lambda can also be a closure. Here’s the same example with a Python lambda function:

def outer_func(x):
y = 4
return lambda z: x + y + z
for i in range(3):
closure = outer_func(i)
print(f"closure({i+5}) = {closure(i+5)}")

When you execute the code above, you obtain the following output:

closure(5) = 9
closure(6) = 11
closure(7) = 13

On line 6, outer_func() returns a lambda and assigns it to to the variable closure. On line 3, the body of the lambda function references x and y. The variable y is available at definition time, whereas x is defined at runtime when outer_func() is invoked.

In this situation, both the normal function and the lambda behave similarly. In the next section, you’ll see a situation where the behavior of a lambda can be deceptive due to its evaluation time (definition time vs runtime).

Evaluation Time

In some situations involving loops, the behavior of a Python lambda function as a closure may be counterintuitive. It requires understanding when free variables are bound in the context of a lambda. The following examples demonstrate the difference when using a regular function vs using a Python lambda.

Test the scenario first using a regular function:

>>> def wrap(n):
... def f():
... print(n)
... return f
...
>>> numbers = 'one', 'two', 'three'
>>> funcs = []
>>> for n in numbers:
... funcs.append(wrap(n))
...
>>> for f in funcs:
... f()
...
one
two
three

In a normal function, n is evaluated at definition time, on line 9, when the function is added to the list: funcs.append(wrap(n)).

Now, with the implementation of the same logic with a lambda function, observe the unexpected behavior:

>>> numbers = 'one', 'two', 'three'
>>> funcs = []
>>> for n in numbers:
... funcs.append(lambda: print(n))
...
>>> for f in funcs:
... f()
...
three
three
three

The unexpected result occurs because the free variable n, as implemented, is bound at the execution time of the lambda expression. The Python lambda function on line 4 is a closure that captures n, a free variable bound at runtime. At runtime, while invoking the function f on line 7, the value of n is three.

To overcome this issue, you can assign the free variable at definition time as follows:

>>> numbers = 'one', 'two', 'three'
>>> funcs = []
>>> for n in numbers:
... funcs.append(lambda n=n: print(n))
...
>>> for f in funcs:
... f()
...
one
two
three

A Python lambda function behaves like a normal function in regard to arguments. Therefore, a lambda parameter can be initialized with a default value: the parameter n takes the outer n as a default value. The Python lambda function could have been written as lambda x=n: print(x) and have the same result.

The Python lambda function is invoked without any argument on line 7, and it uses the default value n set at definition time.

Testing Lambdas

Python lambdas can be tested similarly to regular functions. It’s possible to use both unittest and doctest.

unittest

The unittest module handles Python lambda functions similarly to regular functions:

import unittest

addtwo = lambda x: x + 2

class LambdaTest(unittest.TestCase):
def test_add_two(self):
self.assertEqual(addtwo(2), 4)

def test_add_two_point_two(self):
    self.assertEqual(addtwo(2.2), 4.2)

def test_add_three(self):
    # Should fail
    self.assertEqual(addtwo(3), 6)

if name == 'main':
unittest.main(verbosity=2)

LambdaTest defines a test case with three test methods, each of them exercising a test scenario for addtwo() implemented as a lambda function. The execution of the Python file lambda_unittest.py that contains LambdaTest produces the following:

$ python lambda_unittest.py
test_add_three (main.LambdaTest) ... FAIL
test_add_two (main.LambdaTest) ... ok
test_add_two_point_two (main.LambdaTest) ... ok

======================================================================
FAIL: test_add_three (main.LambdaTest)

Traceback (most recent call last):
File "lambda_unittest.py", line 18, in test_add_three
self.assertEqual(addtwo(3), 6)
AssertionError: 5 != 6


Ran 3 tests in 0.001s

FAILED (failures=1)

As expected, we have two successful test cases and one failure for test_add_three: the result is 5, but the expected result was 6. This failure is due to an intentional mistake in the test case. Changing the expected result from 6 to 5 will satisfy all the tests for LambdaTest.

doctest

The doctest module extracts interactive Python code from docstring to execute tests. Although the syntax of Python lambda functions does not support a typical docstring, it is possible to assign a string to the doc element of a named lambda:

addtwo = lambda x: x + 2
addtwo.doc = """Add 2 to a number.
>>> addtwo(2)
4
>>> addtwo(2.2)
4.2
>>> addtwo(3) # Should fail
6
"""

if name == 'main':
import doctest
doctest.testmod(verbose=True)

The doctest in the doc comment of lambda addtwo() describes the same test cases as in the previous section.

When you execute the tests via doctest.testmod(), you get the following:

$ python lambda_doctest.py
Trying:
addtwo(2)
Expecting:
4
ok
Trying:
addtwo(2.2)
Expecting:
4.2
ok
Trying:
addtwo(3) # Should fail
Expecting:
6


File "lambda_doctest.py", line 16, in main.addtwo
Failed example:
addtwo(3) # Should fail
Expected:
6
Got:
5
1 items had no tests:
main


1 items had failures:
1 of 3 in main.addtwo
3 tests in 2 items.
2 passed and 1 failed.
Test Failed 1 failures.

The failed test results from the same failure explained in the execution of the unit tests in the previous section.

You can add a docstring to a Python lambda via an assignment to doc to document a lambda function. Although possible, the Python syntax better accommodates docstring for normal functions than lambda functions.

Lambda Expression Abuses

Several examples in this article, if written in the context of professional Python code, would qualify as abuses.

If you find yourself trying to overcome something that a lambda expression does not support, this is probably a sign that a normal function would be better suited. The docstring for a lambda expression in the previous section is a good example. Attempting to overcome the fact that a Python lambda function does not support statements is another red flag.

The next sections illustrate a few examples of lambda usages that should be avoided. Those examples might be situations where, in the context of Python lambda, the code exhibits the following pattern:

  • It doesn’t follow the Python style guide (PEP 8)
  • It’s cumbersome and difficult to read.
  • It’s unnecessarily clever at the cost of difficult readability.

Raising an Exception

Trying to raise an exception in a Python lambda should make you think twice. There are some clever ways to do so, but even something like the following is better to avoid:

>>> def throw(ex): raise ex
>>> (lambda: throw(Exception('Something bad happened')))()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
File "<stdin>", line 1, in throw
Exception: Something bad happened

Because a statement is not syntactically correct in a Python lambda body, the workaround in the example above consists of abstracting the statement call with a dedicated function throw(). Using this type of workaround should be avoided. If you encounter this type of code, you should consider refactoring the code to use a regular function.

Cryptic Style

As in any programming languages, you will find Python code that can be difficult to read because of the style used. Lambda functions, due to their conciseness, can be conducive to writing code that is difficult to read.

The following lambda example contains several bad style choices:

>>> (lambda _: list(map(lambda : _ // 2, )))([1,2,3,4,5,6,7,8,9,10])
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]

The underscore () refers to a variable that you don’t need to refer to explicitly. But in this example, three refer to different variables. An initial upgrade to this lambda code could be to name the variables:

>>> (lambda some_list: list(map(lambda n: n // 2,
some_list)))([1,2,3,4,5,6,7,8,9,10])
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]

Admittedly, it’s still difficult to read. By still taking advantage of a lambda, a regular function would go a long way to render this code more readable, spreading the logic over a few lines and function calls:

>>> def div_items(some_list):
div_by_two = lambda n: n // 2
return map(div_by_two, some_list)
>>> list(div_items([1,2,3,4,5,6,7,8,9,10])))
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]

This is still not optimal but shows you a possible path to make code, and Python lambda functions in particular, more readable. In Alternatives to Lambdas, you’ll learn to replace map() and lambda with list comprehensions or generator expressions. This will drastically improve the readability of the code.

Python Classes

You can but should not write class methods as Python lambda functions. The following example is perfectly legal Python code but exhibits unconventional Python code relying on lambda. For example, instead of implementing str as a regular function, it uses a lambda. Similarly, brand and year are properties also implemented with lambda functions, instead of regular functions or decorators:

class Car:
"""Car with methods as lambda functions."""
def init(self, brand, year):
self.brand = brand
self.year = year

brand = property(lambda self: getattr(self, '_brand'),
                 lambda self, value: setattr(self, '_brand', value))

year = property(lambda self: getattr(self, '_year'),
                lambda self, value: setattr(self, '_year', value))

__str__ = lambda self: f'{self.brand} {self.year}'  # 1: error E731

honk = lambda self: print('Honk!')     # 2: error E731

Running a tool like flake8, a style guide enforcement tool, will display the following errors for str and honk:

E731 do not assign a lambda expression, use a def

Although flake8 doesn’t point out an issue for the usage of the Python lambda functions in the properties, they are difficult to read and prone to error because of the usage of multiple strings like '_brand' and '_year'.

Proper implementation of str would be expected to be as follows:

def str(self):
return f'{self.brand} {self.year}'

brand would be written as follows:

@property
def brand(self):
return self._brand

@brand.setter
def brand(self, value):
self._brand = value

As a general rule, in the context of code written in Python, prefer regular functions over lambda expressions. Nonetheless, there are cases that benefit from lambda syntax, as you will see in the next section.

Appropriate Uses of Lambda Expressions

Lambdas in Python tend to be the subject of controversies. Some of the arguments against lambdas in Python are:

  • Issues with readability
  • The imposition of a functional way of thinking
  • Heavy syntax with the lambda keyword

Despite the heated debates questioning the mere existence of this feature in Python, lambda functions have properties that sometimes provide value to the Python language and to developers.

The following examples illustrate scenarios where the use of lambda functions is not only suitable but encouraged in Python code.

Classic Functional Constructs

Lambda functions are regularly used with the built-in functions map() and filter(), as well as functools.reduce(), exposed in the module functools. The following three examples are respective illustrations of using those functions with lambda expressions as companions:

>>> list(map(lambda x: x.upper(), ['cat', 'dog', 'cow']))
['CAT', 'DOG', 'COW']
>>> list(filter(lambda x: 'o' in x, ['cat', 'dog', 'cow']))
['dog', 'cow']
>>> from functools import reduce
>>> reduce(lambda acc, x: f'{acc} | {x}', ['cat', 'dog', 'cow'])
'cat | dog | cow'

You may have to read code resembling the examples above, albeit with more relevant data. For that reason, it’s important to recognize those constructs. Nevertheless, those constructs have equivalent alternatives that are considered more Pythonic. In Alternatives to Lambdas, you’ll learn how to convert higher-order functions and their accompanying lambdas into other more idiomatic forms.

Key Functions

Key functions in Python are higher-order functions that take a parameter key as a named argument. key receives a function that can be a lambda. This function directly influences the algorithm driven by the key function itself. Here are some key functions:

  • sort(): list method
  • sorted(), min(), max(): built-in functions
  • nlargest() and nsmallest(): in the Heap queue algorithm module heapq

Imagine that you want to sort a list of IDs represented as strings. Each ID is the concatenation of the string id and a number. Sorting this list with the built-in function sorted(), by default, uses a lexicographic order as the elements in the list are strings.

To influence the sorting execution, you can assign a lambda to the named argument key, such that the sorting will use the number associated with the ID:

>>> ids = ['id1', 'id2', 'id30', 'id3', 'id22', 'id100']
>>> print(sorted(ids)) # Lexicographic sort
['id1', 'id2', 'id30', 'id3', 'id22', 'id100']
>>> sorted_ids = sorted(ids, key=lambda x: int(x[2:])) # Integer sort
>>> print(sorted_ids)
['id1', 'id2', 'id3', 'id22', 'id30', 'id100']

UI Frameworks

UI frameworks like Tkinter, wxPython, or .NET Windows Forms with IronPython take advantage of lambda functions for mapping actions in response to UI events.

The naive Tkinter program below demonstrates the usage of a lambda assigned to the command of the Reverse button:

import tkinter as tk
import sys

window = tk.Tk()
window.grid_columnconfigure(0, weight=1)
window.title("Lambda")
window.geometry("300x100")
label = tk.Label(window, text="Lambda Calculus")
label.grid(column=0, row=0)
button = tk.Button(
window,
text="Reverse",
command=lambda: label.configure(text=label.cget("text")[::-1]),
)
button.grid(column=0, row=1)
window.mainloop()

Clicking the button Reverse fires an event that triggers the lambda function, changing the label from Lambda Calculus to suluclaC adbmaL*:

Both wxPython and IronPython on the .NET platform share a similar approach for handling events. Note that lambda is one way to handle firing events, but a function may be used for the same purpose. It ends up being self-contained and less verbose to use a lambda when the amount of code needed is very short.

Python Interpreter

When you’re playing with Python code in the interactive interpreter, Python lambda functions are often a blessing. It’s easy to craft a quick one-liner function to explore some snippets of code that will never see the light of day outside of the interpreter. The lambdas written in the interpreter, for the sake of speedy discovery, are like scrap paper that you can throw away after use.

timeit

In the same spirit as the experimentation in the Python interpreter, the module timeit provides functions to time small code fragments. timeit.timeit() in particular can be called directly, passing some Python code in a string. Here’s an example:

>>> from timeit import timeit
>>> timeit("factorial(999)", "from math import factorial", number=10)
0.0013087529951008037

When the statement is passed as a string, timeit() needs the full context. In the example above, this is provided by the second argument that sets up the environment needed by the main function to be timed. Not doing so would raise a NameError exception.

Another approach is to use a lambda:

>>> from math import factorial
>>> timeit(lambda: factorial(999), number=10)
0.0012704220062005334

This solution is cleaner, more readable, and quicker to type in the interpreter. Although the execution time was slightly less for the lambda version, executing the functions again may show a slight advantage for the string version. The execution time of the setup is excluded from the overall execution time and shouldn’t have any impact on the result.

Monkey Patching

For testing, it’s sometimes necessary to rely on repeatable results, even if during the normal execution of a given software, the corresponding results are expected to differ, or even be totally random.

Let’s say you want to test a function that, at runtime, handles random values. But, during the testing execution, you need to assert against predictable values in a repeatable manner. The following example shows how, with a lambda function, monkey patching can help you:

from contextlib import contextmanager
import secrets

def gen_token():
"""Generate a random token."""
return f'TOKEN_{secrets.token_hex(8)}'

@contextmanager
def mock_token():
"""Context manager to monkey patch the secrets.token_hex
function during testing.
"""
default_token_hex = secrets.token_hex
secrets.token_hex = lambda _: 'feedfacecafebeef'
yield
secrets.token_hex = default_token_hex

def test_gen_key():
"""Test the random token."""
with mock_token():
assert gen_token() == f"TOKEN_{'feedfacecafebeef'}"

test_gen_key()

A context manager helps with insulating the operation of monkey patching a function from the standard library (secrets, in this example). The lambda function assigned to secrets.token_hex() substitutes the default behavior by returning a static value.

This allows testing any function depending on token_hex() in a predictable fashion. Prior to exiting from the context manager, the default behavior of token_hex() is reestablished to eliminate any unexpected side effects that would affect other areas of the testing that may depend on the default behavior of token_hex().

Unit test frameworks like unittest and pytest take this concept to a higher level of sophistication.

With pytest, still using a lambda function, the same example becomes more elegant and concise :

import secrets

def gen_token():
return f'TOKEN_{secrets.token_hex(8)}'

def test_gen_key(monkeypatch):
monkeypatch.setattr('secrets.token_hex', lambda : 'feedfacecafebeef')
assert gen_token() == f"TOKEN
{'feedfacecafebeef'}"

With the pytest monkeypatch fixture, secrets.token_hex() is overwritten with a lambda that will return a deterministic value, feedfacecafebeef, allowing to validate the test. The pytest monkeypatch fixture allows you to control the scope of the override. In the example above, invoking secrets.token_hex() in subsequent tests, without using monkey patching, would execute the normal implementation of this function.

Executing the pytest test gives the following result:

$ pytest test_token.py -v
============================= test session starts ==============================
platform linux -- Python 3.7.2, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
cachedir: .pytest_cache
rootdir: /home/andre/AB/tools/bpython, inifile:
collected 1 item

test_token.py::test_gen_key PASSED [100%]

=========================== 1 passed in 0.01 seconds ===========================

The test passes as we validated that the gen_token() was exercised, and the results were the expected ones in the context of the test.

Alternatives to Lambdas

While there are great reasons to use lambda, there are instances where its use is frowned upon. So what are the alternatives?

Higher-order functions like map(), filter(), and functools.reduce() can be converted to more elegant forms with slight twists of creativity, in particular with list comprehensions or generator expressions.

Map

The built-in function map() takes a function as a first argument and applies it to each of the elements of its second argument, an iterable. Examples of iterables are strings, lists, and tuples.

map() returns an iterator corresponding to the transformed collection. As an example, if you wanted to transform a list of strings to a new list with each string capitalized, you could use map(), as follows:

>>> list(map(lambda x: x.capitalize(), ['cat', 'dog', 'cow']))
['Cat', 'Dog', 'Cow']

You need to invoke list() to convert the iterator returned by map() into an expanded list that can be displayed in the Python shell interpreter.

Using a list comprehension eliminates the need for defining and invoking the lambda function:

>>> [x.capitalize() for x in ['cat', 'dog', 'cow']]
['Cat', 'Dog', 'Cow']

Filter

The built-in function filter(), another classic functional construct, can be converted into a list comprehension. It takes a predicate as a first argument and an iterable as a second argument. It builds an iterator containing all the elements of the initial collection that satisfies the predicate function. Here’s an example that filters all the even numbers in a given list of integers:

>>> even = lambda x: x%2 == 0
>>> list(filter(even, range(11)))
[0, 2, 4, 6, 8, 10]

Note that filter() returns an iterator, hence the need to invoke the built-in type list that constructs a list given an iterator.

The implementation leveraging the list comprehension construct gives the following:

>>> [x for x in range(11) if x%2 == 0]
[0, 2, 4, 6, 8, 10]

Reduce

Since Python 3, reduce() has gone from a built-in function to a functools module function. As map() and filter(), its first two arguments are respectively a function and an iterable. It may also take an initializer as a third argument that is used as the initial value of the resulting accumulator. For each element of the iterable, reduce() applies the function and accumulates the result that is returned when the iterable is exhausted.

To apply reduce() to a list of pairs and calculate the sum of the first item of each pair, you could write this:

>>> import functools
>>> pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> functools.reduce(lambda acc, pair: acc + pair[0], pairs, 0)
6

A more idiomatic approach using a generator expression, as an argument to sum() in the example, is the following:

>>> pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> sum(x[0] for x in pairs)
6

A slightly different and possibly cleaner solution removes the need to explicitly access the first element of the pair and instead use unpacking:

>>> pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> sum(x for x, _ in pairs)
6

The use of underscore (_) is a Python convention indicating that you can ignore the second value of the pair.

sum() takes a unique argument, so the generator expression does not need to be in parentheses.

Are Lambdas Pythonic or Not?

PEP 8, which is the style guide for Python code, reads:

Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier. (Source)

This strongly discourages using lambda bound to an identifier, mainly where functions should be used and have more benefits. PEP 8 does not mention other usages of lambda. As you have seen in the previous sections, lambda functions may certainly have good uses, although they are limited.

A possible way to answer the question is that lambda functions are perfectly Pythonic if there is nothing more Pythonic available. I’m staying away from defining what “Pythonic” means, leaving you with the definition that best suits your mindset, as well as your personal or your team’s coding style.

Conclusion

You now know how to use Python lambda functions and can:

  • Write Python lambdas and use anonymous functions
  • Choose wisely between lambdas or normal Python functions
  • Avoid excessive use of lambdas
  • Use lambdas with higher-order functions or Python key functions

If you have a penchant for mathematics, you may have some fun exploring the fascinating world of lambda calculus.

Python lambdas are like salt. A pinch in your spam, ham, and eggs will enhance the flavors, but too much will spoil the dish.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

Python Tutorial - Python GUI Programming - Python GUI Examples (Tkinter Tutorial)

Python Lambda Functions Tutorial with Examples

A Complete Machine Learning Project Walk-Through in Python

Python Programming Tutorial - Full Course for Beginners


What's Python IDLE? How to use Python IDLE to interact with Python?

What's Python IDLE? How to use Python IDLE to interact with Python?

In this tutorial, you’ll learn all the basics of using **IDLE** to write Python programs. You'll know what Python IDLE is and how you can use it to interact with Python directly. You’ve also learned how to work with Python files and customize Python IDLE to your liking.

In this tutorial, you'll learn how to use the development environment included with your Python installation. Python IDLE is a small program that packs a big punch! You'll learn how to use Python IDLE to interact with Python directly, work with Python files, and improve your development workflow.

If you’ve recently downloaded Python onto your computer, then you may have noticed a new program on your machine called IDLE. You might be wondering, “What is this program doing on my computer? I didn’t download that!” While you may not have downloaded this program on your own, IDLE comes bundled with every Python installation. It’s there to help you get started with the language right out of the box. In this tutorial, you’ll learn how to work in Python IDLE and a few cool tricks you can use on your Python journey!

In this tutorial, you’ll learn:

  • What Python IDLE is
  • How to interact with Python directly using IDLE
  • How to edit, execute, and debug Python files with IDLE
  • How to customize Python IDLE to your liking

Table of Contents

What Is Python IDLE?

Every Python installation comes with an Integrated Development and Learning Environment, which you’ll see shortened to IDLE or even IDE. These are a class of applications that help you write code more efficiently. While there are many IDEs for you to choose from, Python IDLE is very bare-bones, which makes it the perfect tool for a beginning programmer.

Python IDLE comes included in Python installations on Windows and Mac. If you’re a Linux user, then you should be able to find and download Python IDLE using your package manager. Once you’ve installed it, you can then use Python IDLE as an interactive interpreter or as a file editor.

An Interactive Interpreter

The best place to experiment with Python code is in the interactive interpreter, otherwise known as a shell. The shell is a basic Read-Eval-Print Loop (REPL). It reads a Python statement, evaluates the result of that statement, and then prints the result on the screen. Then, it loops back to read the next statement.

The Python shell is an excellent place to experiment with small code snippets. You can access it through the terminal or command line app on your machine. You can simplify your workflow with Python IDLE, which will immediately start a Python shell when you open it.

A File Editor

Every programmer needs to be able to edit and save text files. Python programs are files with the .py extension that contain lines of Python code. Python IDLE gives you the ability to create and edit these files with ease.

Python IDLE also provides several useful features that you’ll see in professional IDEs, like basic syntax highlighting, code completion, and auto-indentation. Professional IDEs are more robust pieces of software and they have a steep learning curve. If you’re just beginning your Python programming journey, then Python IDLE is a great alternative!

How to Use the Python IDLE Shell

The shell is the default mode of operation for Python IDLE. When you click on the icon to open the program, the shell is the first thing that you see:

This is a blank Python interpreter window. You can use it to start interacting with Python immediately. You can test it out with a short line of code:

Here, you used print() to output the string "Hello, from IDLE!" to your screen. This is the most basic way to interact with Python IDLE. You type in commands one at a time and Python responds with the result of each command.

Next, take a look at the menu bar. You’ll see a few options for using the shell:

You can restart the shell from this menu. If you select that option, then you’ll clear the state of the shell. It will act as though you’ve started a fresh instance of Python IDLE. The shell will forget about everything from its previous state:

In the image above, you first declare a variable, x = 5. When you call print(x), the shell shows the correct output, which is the number 5. However, when you restart the shell and try to call print(x) again, you can see that the shell prints a traceback. This is an error message that says the variable x is not defined. The shell has forgotten about everything that came before it was restarted.

You can also interrupt the execution of the shell from this menu. This will stop any program or statement that’s running in the shell at the time of interruption. Take a look at what happens when you send a keyboard interrupt to the shell:

A KeyboardInterrupt error message is displayed in red text at the bottom of your window. The program received the interrupt and has stopped executing.

How to Work With Python Files

Python IDLE offers a full-fledged file editor, which gives you the ability to write and execute Python programs from within this program. The built-in file editor also includes several features, like code completion and automatic indentation, that will speed up your coding workflow. First, let’s take a look at how to write and execute programs in Python IDLE.

Opening a File

To start a new Python file, select File → New File from the menu bar. This will open a blank file in the editor, like this:

From this window, you can write a brand new Python file. You can also open an existing Python file by selecting File → Open… in the menu bar. This will bring up your operating system’s file browser. Then, you can find the Python file you want to open.

If you’re interested in reading the source code for a Python module, then you can select File → Path Browser. This will let you view the modules that Python IDLE can see. When you double click on one, the file editor will open up and you’ll be able to read it.

The content of this window will be the same as the paths that are returned when you call sys.path. If you know the name of a specific module you want to view, then you can select File → Module Browser and type in the name of the module in the box that appears.

Editing a File

Once you’ve opened a file in Python IDLE, you can then make changes to it. When you’re ready to edit a file, you’ll see something like this:

The contents of your file are displayed in the open window. The bar along the top of the window contains three pieces of important information:

  1. The name of the file that you’re editing
  2. The full path to the folder where you can find this file on your computer
  3. The version of Python that IDLE is using

In the image above, you’re editing the file myFile.py, which is located in the Documents folder. The Python version is 3.7.1, which you can see in parentheses.

There are also two numbers in the bottom right corner of the window:

  1. Ln: shows the line number that your cursor is on.
  2. Col: shows the column number that your cursor is on.

It’s useful to see these numbers so that you can find errors more quickly. They also help you make sure that you’re staying within a certain line width.

There are a few visual cues in this window that will help you remember to save your work. If you look closely, then you’ll see that Python IDLE uses asterisks to let you know that your file has unsaved changes:

The file name shown in the top of the IDLE window is surrounded by asterisks. This means that there are unsaved changes in your editor. You can save these changes with your system’s standard keyboard shortcut, or you can select File → Save from the menu bar. Make sure that you save your file with the .py extension so that syntax highlighting will be enabled.

Executing a File

When you want to execute a file that you’ve created in IDLE, you should first make sure that it’s saved. Remember, you can see if your file is properly saved by looking for asterisks around the filename at the top of the file editor window. Don’t worry if you forget, though! Python IDLE will remind you to save whenever you attempt to execute an unsaved file.

To execute a file in IDLE, simply press the F5 key on your keyboard. You can also select Run → Run Module from the menu bar. Either option will restart the Python interpreter and then run the code that you’ve written with a fresh interpreter. The process is the same as when you run python3 -i [filename] in your terminal.

When your code is done executing, the interpreter will know everything about your code, including any global variables, functions, and classes. This makes Python IDLE a great place to inspect your data if something goes wrong. If you ever need to interrupt the execution of your program, then you can press Ctrl+C in the interpreter that’s running your code.

How to Improve Your Workflow

Now that you’ve seen how to write, edit, and execute files in Python IDLE, it’s time to speed up your workflow! The Python IDLE editor offers a few features that you’ll see in most professional IDEs to help you code faster. These features include automatic indentation, code completion and call tips, and code context.

Automatic Indentation

IDLE will automatically indent your code when it needs to start a new block. This usually happens after you type a colon (:). When you hit the enter key after the colon, your cursor will automatically move over a certain number of spaces and begin a new code block.

You can configure how many spaces the cursor will move in the settings, but the default is the standard four spaces. The developers of Python agreed on a standard style for well-written Python code, and this includes rules on indentation, whitespace, and more. This standard style was formalized and is now known as PEP 8. To learn more about it, check out How to Write Beautiful Python Code With PEP 8.

Code Completion and Call Tips

When you’re writing code for a large project or a complicated problem, you can spend a lot of time just typing out all of the code you need. Code completion helps you save typing time by trying to finish your code for you. Python IDLE has basic code completion functionality. It can only autocomplete the names of functions and classes. To use autocompletion in the editor, just press the tab key after a sequence of text.

Python IDLE will also provide call tips. A call tip is like a hint for a certain part of your code to help you remember what that element needs. After you type the left parenthesis to begin a function call, a call tip will appear if you don’t type anything for a few seconds. For example, if you can’t quite remember how to append to a list, then you can pause after the opening parenthesis to bring up the call tip:

The call tip will display as a popup note, reminding you how to append to a list. Call tips like these provide useful information as you’re writing code.

Code Context

The code context functionality is a neat feature of the Python IDLE file editor. It will show you the scope of a function, class, loop, or other construct. This is particularly useful when you’re scrolling through a lengthy file and need to keep track of where you are while reviewing code in the editor.

To turn it on, select Options → Code Context in the menu bar. You’ll see a gray bar appear at the top of the editor window:

As you scroll down through your code, the context that contains each line of code will stay inside of this gray bar. This means that the print() functions you see in the image above are a part of a main function. When you reach a line that’s outside the scope of this function, the bar will disappear.

How to Debug in IDLE

A bug is an unexpected problem in your program. They can appear in many forms, and some are more difficult to fix than others. Some bugs are tricky enough that you won’t be able to catch them by just reading through your program. Luckily, Python IDLE provides some basic tools that will help you debug your programs with ease!

Interpreter DEBUG Mode

If you want to run your code with the built-in debugger, then you’ll need to turn this feature on. To do so, select Debug → Debugger from the Python IDLE menu bar. In the interpreter, you should see [DEBUG ON] appear just before the prompt (>>>), which means the interpreter is ready and waiting.

When you execute your Python file, the debugger window will appear:

In this window, you can inspect the values of your local and global variables as your code executes. This gives you insight into how your data is being manipulated as your code runs.

You can also click the following buttons to move through your code:

  • Go: Press this to advance execution to the next breakpoint. You’ll learn about these in the next section.
  • Step: Press this to execute the current line and go to the next one.
  • Over: If the current line of code contains a function call, then press this to step over that function. In other words, execute that function and go to the next line, but don’t pause while executing the function (unless there is a breakpoint).
  • Out: If the current line of code is in a function, then press this to step out of this function. In other words, continue the execution of this function until you return from it.

Be careful, because there is no reverse button! You can only step forward in time through your program’s execution.

You’ll also see four checkboxes in the debug window:

  1. Globals: your program’s global information
  2. Locals: your program’s local information during execution
  3. Stack: the functions that run during execution
  4. Source: your file in the IDLE editor

When you select one of these, you’ll see the relevant information in your debug window.

Breakpoints

A breakpoint is a line of code that you’ve identified as a place where the interpreter should pause while running your code. They will only work when DEBUG mode is turned on, so make sure that you’ve done that first.

To set a breakpoint, right-click on the line of code that you wish to pause. This will highlight the line of code in yellow as a visual indication of a set breakpoint. You can set as many breakpoints in your code as you like. To undo a breakpoint, right-click the same line again and select Clear Breakpoint.

Once you’ve set your breakpoints and turned on DEBUG mode, you can run your code as you would normally. The debugger window will pop up, and you can start stepping through your code manually.

Errors and Exceptions

When you see an error reported to you in the interpreter, Python IDLE lets you jump right to the offending file or line from the menu bar. All you have to do is highlight the reported line number or file name with your cursor and select Debug → Go to file/line from the menu bar. This is will open up the offending file and take you to the line that contains the error. This feature works regardless of whether or not DEBUG mode is turned on.

Python IDLE also provides a tool called a stack viewer. You can access it under the Debug option in the menu bar. This tool will show you the traceback of an error as it appears on the stack of the last error or exception that Python IDLE encountered while running your code. When an unexpected or interesting error occurs, you might find it helpful to take a look at the stack. Otherwise, this feature can be difficult to parse and likely won’t be useful to you unless you’re writing very complicated code.

How to Customize Python IDLE

There are many ways that you can give Python IDLE a visual style that suits you. The default look and feel is based on the colors in the Python logo. If you don’t like how anything looks, then you can almost always change it.

To access the customization window, select Options → Configure IDLE from the menu bar. To preview the result of a change you want to make, press Apply. When you’re done customizing Python IDLE, press OK to save all of your changes. If you don’t want to save your changes, then simply press Cancel.

There are 5 areas of Python IDLE that you can customize:

  1. Fonts/Tabs
  2. Highlights
  3. Keys
  4. General
  5. Extensions

Let’s take a look at each of them now.

Fonts/Tabs

The first tab allows you to change things like font color, font size, and font style. You can change the font to almost any style you like, depending on what’s available for your operating system. The font settings window looks like this:

You can use the scrolling window to select which font you prefer. (I recommend you select a fixed-width font like Courier New.) Pick a font size that’s large enough for you to see well. You can also click the checkbox next to Bold to toggle whether or not all text appears in bold.

This window will also let you change how many spaces are used for each indentation level. By default, this will be set to the PEP 8 standard of four spaces. You can change this to make the width of your code more or less spread out to your liking.

Highlights

The second customization tab will let you change highlights. Syntax highlighting is an important feature of any IDE that highlights the syntax of the language that you’re working in. This helps you visually distinguish between the different Python constructs and the data used in your code.

Python IDLE allows you to fully customize the appearance of your Python code. It comes pre-installed with three different highlight themes:

  1. IDLE Day
  2. IDLE Night
  3. IDLE New

You can select from these pre-installed themes or create your own custom theme right in this window:

Unfortunately, IDLE does not allow you to install custom themes from a file. You have to create customs theme from this window. To do so, you can simply start changing the colors for different items. Select an item, and then press Choose color for. You’ll be brought to a color picker, where you can select the exact color that you want to use.

You’ll then be prompted to save this theme as a new custom theme, and you can enter a name of your choosing. You can then continue changing the colors of different items if you’d like. Remember to press Apply to see your changes in action!

Keys

The third customization tab lets you map different key presses to actions, also known as keyboard shortcuts. These are a vital component of your productivity whenever you use an IDE. You can either come up with your own keyboard shortcuts, or you can use the ones that come with IDLE. The pre-installed shortcuts are a good place to start:

The keyboard shortcuts are listed in alphabetical order by action. They’re listed in the format Action - Shortcut, where Action is what will happen when you press the key combination in Shortcut. If you want to use a built-in key set, then select a mapping that matches your operating system. Pay close attention to the different keys and make sure your keyboard has them!

Creating Your Own Shortcuts

The customization of the keyboard shortcuts is very similar to the customization of syntax highlighting colors. Unfortunately, IDLE does not allow you to install custom keyboard shortcuts from a file. You must create a custom set of shortcuts from the Keys tab.

Select one pair from the list and press Get New Keys for Selection. A new window will pop up:

Here, you can use the checkboxes and scrolling menu to select the combination of keys that you want to use for this shortcut. You can select Advanced Key Binding Entry >> to manually type in a command. Note that this cannot pick up the keys you press. You have to literally type in the command as you see it displayed to you in the list of shortcuts.

General

The fourth tab of the customization window is a place for small, general changes. The general settings tab looks like this:

Here, you can customize things like the window size and whether the shell or the file editor opens first when you start Python IDLE. Most of the things in this window are not that exciting to change, so you probably won’t need to fiddle with them much.

Extensions

The fifth tab of the customization window lets you add extensions to Python IDLE. Extensions allow you to add new, awesome features to the editor and the interpreter window. You can download them from the internet and install them to right into Python IDLE.

To view what extensions are installed, select Options → Configure IDLE -> Extensions. There are many extensions available on the internet for you to read more about. Find the ones you like and add them to Python IDLE!

Conclusion

In this tutorial, you’ve learned all the basics of using IDLE to write Python programs. You know what Python IDLE is and how you can use it to interact with Python directly. You’ve also learned how to work with Python files and customize Python IDLE to your liking.

You’ve learned how to:

  • Work with the Python IDLE shell
  • Use Python IDLE as a file editor
  • Improve your workflow with features to help you code faster
  • Debug your code and view errors and exceptions
  • Customize Python IDLE to your liking

Now you’re armed with a new tool that will let you productively write Pythonic code and save you countless hours down the road. Happy programming!