Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Thinking Recursively in Python Show Image: xkcd.com Problems (in life and also in computer science) can often seem big and scary. But if we keep chipping away at them, more often than not we can break them down into smaller chunks trivial enough to solve. This is the essence of thinking recursively, and my aim in this article is to provide you, my dear reader, with the conceptual tools necessary to approach problems from this recursive point of view. Together, we’ll learn how to work with recursion in our Python programs by mastering concepts such as recursive functions and recursive data structures. We’ll also talk about maintaining state during recursion and avoiding recomputation by caching results. This is going to be a lot of fun. Onwards and upwards! Dear Pythonic Santa Claus…I realize that as fellow Pythonistas we are all consenting adults here, but children seem to grok the beauty of recursion better. So let’s not be adults here for a moment and talk about how we can use recursion to help Santa Claus. Have you ever wondered how Christmas presents are delivered? I sure have, and I believe Santa Claus has a list of houses he loops through. He goes to a house, drops off the presents, eats the cookies and milk, and moves on to the next house on the list. Since this algorithm for delivering presents is based on an explicit loop construction, it is called an iterative algorithm. The algorithm for iterative present delivery implemented in Python:
>>>
But I feel for Santa. At his age, he shouldn’t have to deliver all the presents by himself. I propose an algorithm with which he can divide the work of delivering presents among his elves:
This is the typical structure of a recursive algorithm. If the current problem represents a simple case, solve it. If not, divide it into subproblems and apply the same strategy to them. The algorithm for recursive present delivery implemented in Python:
>>>
Recursive Functions in PythonNow that we have some intuition about recursion, let’s introduce the formal definition of a recursive function. A recursive function is a function defined in terms of itself via self-referential expressions. This means that the function will continue to call itself and repeat its behavior until some condition is met to return a result. All recursive functions share a common structure made up of two parts: base case and recursive case. To demonstrate this structure, let’s write a recursive function for calculating
Here, Recursive function for calculating
>>>
Behind the scenes, each recursive call adds a stack frame (containing its execution context) to the call stack until we reach the base case. Then, the stack begins to unwind as each call returns its results: Maintaining StateWhen dealing with recursive functions, keep in mind that each recursive call has its own execution context, so to maintain state during recursion you have to either:
A demonstration
should make things clearer. Let’s calculate Here’s how you do that by threading it through each recursive call (i.e. passing the updated current state to each recursive call as arguments):
>>>
Here’s how you maintain the state by keeping it in global scope:
>>>
I prefer threading the state through each recursive call because I find global mutable state to be evil, but that’s a discussion for a later time. Recursive Data Structures in PythonA data structure is recursive if it can be defined in terms of a smaller version of itself. A list is an example of a recursive data structure. Let me demonstrate. Assume that you have only an empty list at your disposal, and the only operation you can perform on it is this:
Using the empty list and the
List is not the only recursive data structure. Other examples include set, tree, dictionary, etc. Recursive data structures and recursive functions go together like bread and butter. The recursive function’s structure can often be modeled after the definition of the recursive data structure it takes as an input. Let me demonstrate this by calculating the sum of all the elements of a list recursively:
>>>
Naive Recursion is NaiveThe Fibonacci numbers were originally defined by the Italian mathematician Fibonacci in the thirteenth century to model the growth of rabbit populations. Fibonacci surmised that the number of pairs of rabbits born in a given year is equal to the number of pairs of rabbits born in each of the two previous years, starting from one pair of rabbits in the first year. To count the number of rabbits born in the nth year, he defined the recurrence relation: Fn = Fn-1 + Fn-2 The base cases are: F0 = 0 and F1 = 1 Let’s write a recursive function to compute the nth Fibonacci number:
>>>
Naively following the recursive definition of the nth Fibonacci number was rather
inefficient. As you can see from the output above, we are unnecessarily recomputing values. Let’s try to improve
>>>
Pesky DetailsPython doesn’t have support for tail-call elimination. As a result, you can cause a stack overflow if you end up using more stack frames than the default call stack depth: >>>
Keep this limitation in mind if you have a program that requires deep recursion. Also, Python’s mutable data structures don’t support structural sharing, so treating them like immutable data structures is going to negatively affect your space and GC (garbage collection) efficiency because you are going to end up unnecessarily copying a lot of mutable objects. For example, I have used this pattern to decompose lists and recurse over them: >>>
I did that to simplify things for the sake of clarity. Keep in mind that tail is being created by copying. Recursively doing that over large lists can negatively affect your space and GC efficiency. FinI was once asked to explain recursion in an interview. I took a sheet of paper and wrote References
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Thinking Recursively in Python How do you solve recursion problems?Step 1) Know what your function should do. ... . Step 2) Pick a subproblem and assume your function already works on it. ... . Step 3) Take the answer to your subproblem, and use it to solve for the original problem. ... . Step 4) You have already solved 99% of the problem.. What is recursive problem solving give example?Recursion is the process of defining a problem (or the solution to a problem) in terms of (a simpler version of) itself. For example, we can define the operation "find your way home" as: If you are at home, stop moving. Take one step toward home.
How do you break a recursion in Python?One way to break out of a recursive function in Python is to throw an exception and catch that at the top level. Some people will say that this is not the right way to think about recursion, but it gets the job done.
|