Lambda Functions, Recursion, and Generators
On this page
Lambda Functions — Quick, Anonymous FunctionsRecursion — A Function That Calls ItselfGenerators — Producing Data EfficientlyExampleUsingnext() ManuallyWhy Use Generators?Mini Project — Random Quote StreamAs you become more comfortable with Python functions, you’ll discover that they can be written and used in different ways.
In this section, we explore three powerful techniques that make Python functions more expressive and efficient: lambda functions, recursion, and generators.
Lambda Functions — Quick, Anonymous Functions
Sometimes, you need a small function only once, such as when sorting data or filtering a list. Instead of writing a full def block, Python allows you to create anonymous functions using the lambda keyword.
A lambda function can have any number of arguments, but only one expression. The expression is automatically returned.
square = lambda x: x ** 2
print(square(5))Output
25
This is equivalent to:
def square(x):
return x ** 2Lambda functions are often used with built-in functions like map(),filter(), or sorted().
For example:
numbers = [3, 6, 9, 2, 5]
doubled = list(map(lambda x: x * 2, numbers))
print(doubled)Output
[6, 12, 18, 4, 10]
Here,map() applies the lambda function to each element of the list — doubling all numbers without needing a separate function definition.
Recursion — A Function That Calls Itself
Recursion is a technique where a function calls itself to solve a smaller version of the same problem. It is often used in mathematical operations or tasks that naturally repeat with smaller inputs — such as calculating factorials or navigating nested data.
For a nonnegative integer n, the factorial is the product of the integers from 1 to n; 0! is 1. This example assumes a nonnegative integer input.
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)print(factorial(5))Output
120
Here’s what happens:
1.factorial(5) calls factorial(4) 2.factorial(4) calls factorial(3) and so on 3. When n == 0, the recursion stops (base case) 4. The results are multiplied as the calls return.
It’s important to always include a base case, otherwise the function will call itself forever and cause a recursion error.
Generators — Producing Data Efficiently
Generators are functions that can pause and resume their execution.
When a generator function is called, it returns a generator object, which is an iterator.
Its body has not started running. Execution begins when a value is requested, through iteration or next().
yield supplies a value and pauses execution. A return or the end of the body finishes the generator.
Example
Here’s an example that generates numbers up to a limit:
def count_up_to(n):
count = 1
while count <= n:
yield count
count += 1
# Create a generator
numbers = count_up_to(5)
# Iterate through values one by one
for num in numbers:
print(num)Output
1
2
3
4
5
Here’s what happens step by step:
- The function
count_up_to()is called, but it doesn’t run completely—it returns a generator object. - Each iteration in the
forloop triggers the nextyieldstatement. - The function pauses after yielding each number, and resumes the next time the loop requests a new value.
Using next() Manually
You can also control generators manually with the next() function, which retrieves the next yielded value each time it’s called.
gen = count_up_to(3)
print(next(gen))
print(next(gen))
print(next(gen))Output
1
2
3
Why Use Generators?
Generators are memory-efficient because they produce one value at a time instead of creating an entire list in memory. This makes them especially powerful when working with large sequences or infinite streams of data.
For instance, compare a generator to building a list directly:
# Regular list - builds all items at once
nums_list = [i for i in range(1000000)]
# Generator - builds items on demand
nums_gen = (i for i in range(1000000))The list version stores one million numbers in memory.
The generator version, using parentheses ( ), produces numbers on demand, saving resources.
Mini Project — Random Quote Stream
Let’s use a generator to simulate an ongoing stream of random quotes every time the user requests one. It combines your knowledge of functions, generators, and the random module.
import random
def quote_stream():
quotes = [
"Keep learning, keep growing.",
"Code is like humor — when you have to explain it, it’s bad.",
"Simplicity is the soul of efficiency.",
"In theory, there’s no difference between theory and practice."
]
while True:
yield random.choice(quotes)
# Create a generator
stream = quote_stream()
# Get three random quotes
print(next(stream))
print(next(stream))
print(next(stream))Output — one possible run
Simplicity is the soul of efficiency.
Keep learning, keep growing.
Simplicity is the soul of efficiency.
Each call to next(stream) retrieves a new random quote, while the generator keeps running indefinitely until stopped.
This demonstrates how generators can power infinite or dynamic data flows efficiently.