For working professionals
For fresh graduates
More
13. Print In Python
15. Python for Loop
19. Break in Python
23. Float in Python
25. List in Python
27. Tuples in Python
29. Set in Python
53. Python Modules
57. Python Packages
59. Class in Python
61. Object in Python
73. JSON Python
79. Python Threading
84. Map in Python
85. Filter in Python
86. Eval in Python
96. Sort in Python
101. Datetime Python
103. 2D Array in Python
104. Abs in Python
105. Advantages of Python
107. Append in Python
110. Assert in Python
113. Bool in Python
115. chr in Python
118. Count in python
119. Counter in Python
121. Datetime in Python
122. Extend in Python
123. F-string in Python
125. Format in Python
131. Index in Python
132. Interface in Python
134. Isalpha in Python
136. Iterator in Python
137. Join in Python
140. Literals in Python
141. Matplotlib
144. Modulus in Python
147. OpenCV Python
149. ord in Python
150. Palindrome in Python
151. Pass in Python
156. Python Arrays
158. Python Frameworks
160. Python IDE
164. Python PIP
165. Python Seaborn
166. Python Slicing
168. Queue in Python
169. Replace in Python
173. Stack in Python
174. scikit-learn
175. Selenium with Python
176. Self in Python
177. Sleep in Python
179. Split in Python
184. Strip in Python
185. Subprocess in Python
186. Substring in Python
195. What is Pygame
197. XOR in Python
198. Yield in Python
199. Zip in Python
In this tutorial, we delve deep into the concept of recursion in Python. While recursion is widely acknowledged in the programming world, its usage and nuances in Python require special attention. Aimed at professionals, this guide not only explicates the very essence of recursion in Python but also uncovers its practical implementations, variations, and efficiencies.
Recursion, often revered for its elegance, is a cornerstone of algorithmic logic. Recursion in Python is not just a method, but an approach, leveraging the very essence of problem-solving. Breaking down a problem into sub-problems, recursion employs a self-reference mechanism to navigate challenges.
In programming, different paradigms exist to solve problems efficiently. One such paradigm, particularly prominent in Python, is recursion. But what exactly is recursion?
At its core, recursion is a technique where a function calls itself, aiming to simplify a complex problem by breaking it down into more manageable components. This is analogous to approaching a vast and intricate jigsaw puzzle. Instead of being daunted by the complete picture, you would typically start with smaller sections, methodically working your way through individual pieces until the whole puzzle comes together. This step-by-step approach, focusing on smaller parts to make sense of the bigger picture, mirrors the essence of a recursive function in programming.
Diving deeper into Python’s perspective on recursion, the language has a distinct approach. When a function in Python refers to itself during its execution, this self-reference is termed a "recursive call." However, it's essential to ensure that these recursive calls don't continue indefinitely. Hence, Python employs a memory mechanism known as the stack. Every time a function calls itself, the details of this call get stored in this stack. This method is instrumental because it remembers previous calls and their respective states. The stack then patiently waits for a "base case" to be reached.
This base case is crucial. It's a predefined condition that dictates when the function should stop calling itself, thus preventing an infinite loop. Once this base case is met, Python starts unwinding, processing the stored calls from the stack. Each call's result is then computed in sequence, with the final outcome often being a cumulative result of all these individual calls.
Understanding recursion, especially in Python, demands more than just knowing its definition. It requires an appreciation for its elegance, its ability to make challenging problems more digestible, and its potent combination of simplicity and depth. It's a tool that, when wielded correctly, can lead to beautifully efficient and concise solutions in programming.
Recursion, as we've seen, is a powerful tool in the programmer's arsenal. Within the broader umbrella of recursion, there's a particular subtype known as tail recursion. This variant holds a special place due to its unique characteristics and advantages, especially concerning optimization.
To understand tail recursion, one must first grasp its distinction from standard recursion. In traditional recursion, a function may perform multiple operations after the recursive call. Contrarily, in tail recursion, the function's recursive call stands as its final act, meaning there are no operations left post this call. This seemingly minute difference in structure has a ripple effect on how functions are executed and how they utilize memory.
Delving into memory management, one of the notable challenges with standard recursion is its appetite for memory. Each recursive call demands storage for its operational details. As the stack of calls grows, the memory usage can quickly balloon, potentially leading to stack overflows.
Tail recursion, with its streamlined approach, sidesteps this problem. Since there are no operations post the recursive call, there’s no need for the system to remember the state of previous calls. This means that the memory for one call can be "reused" for the next, conserving memory and minimizing the risk of stack overflows. This optimization is especially beneficial in languages that are tailored to recognize and enhance tail recursion.
But what if one is faced with a non-tail recursive function and wishes to harness the benefits of tail recursion? Fortunately, there's a way. Often, these functions can undergo transformation to adopt the tail-recursive model. A common technique involves using "accumulators." These are variables designed to hold intermediate results, enabling the function to offload operations before the recursive call, thus adhering to the tail-recursive structure.
Tail recursion is not just a theoretical concept but a practical technique that addresses real-world programming challenges. By ensuring that the recursive call is the final action, it unlocks efficiencies and optimizations, making recursive solutions more robust and scalable.
Code:
def find_number_recursive(numbers, target, index=0):
if index >= len(numbers):
return False
if numbers[index] == target:
return True
return find_number_recursive(numbers, target, index + 1)
# Example usage
numbers_list = [2, 5, 8, 10, 15]
target_number = 10
if find_number_recursive(numbers_list, target_number):
print(f"The number {target_number} was found in the list.")
else:
print(f"The number {target_number} was not found in the list.")
Code:
def fibonacci_recursive(n):
if n <= 0:
return 0
elif n == 1:
return 1
else:
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)
# Example usage
n_terms = 10 # Number of terms in the Fibonacci sequence
for i in range(n_terms):
print(f"F({i}) =", fibonacci_recursive(i))
Code:
def sum_of_natural_numbers_recursive(n):
if n <= 0:
return 0
else:
return n + sum_of_natural_numbers_recursive(n - 1)
# Example usage
n = 5 # Number of terms
sum_result = sum_of_natural_numbers_recursive(n)
print(f"The sum of the first {n} natural numbers is:", sum_result)
Code:
def power_recursive(base, exponent):
if exponent == 0:
return 1
else:
return base * power_recursive(base, exponent - 1)
# Example usage
base = 2
exponent = 3
result = power_recursive(base, exponent)
print(f"{base} raised to the power of {exponent} is:", result)
Code:
def gcd_recursive(a, b):
if b == 0:
return a
else:
return gcd_recursive(b, a % b)
def lcm_recursive(a, b):
return (a * b) // gcd_recursive(a, b)
# Example usage
num1 = 12
num2 = 18
lcm_result = lcm_recursive(num1, num2)
print(f"The LCM of {num1} and {num2} is:", lcm_result)
Code:
def gcd_recursive(a, b):
if b == 0:
return a
else:
return gcd_recursive(b, a % b)
# Example usage
num1 = 48
num2 = 18
gcd_result = gcd_recursive(num1, num2)
print(f"The GCD of {num1} and {num2} is:", gcd_result)
Code:
def tower_of_hanoi(n, source, target, auxiliary):
if n == 1:
print(f"Move disk 1 from {source} to {target}")
return
tower_of_hanoi(n - 1, source, auxiliary, target)
print(f"Move disk {n} from {source} to {target}")
tower_of_hanoi(n - 1, auxiliary, target, source)
# Example usage
num_disks = 3
tower_of_hanoi(num_disks, 'A', 'C', 'B')
Code:
def sum_of_digits_recursive(number):
if number == 0:
return 0
else:
return number % 10 + sum_of_digits_recursive(number // 10)
# Example usage
num = 12345
sum_result = sum_of_digits_recursive(num)
print(f"The sum of digits in {num} is:", sum_result)
Code:
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]
left_half = merge_sort(left_half)
right_half = merge_sort(right_half)
return merge(left_half, right_half)
def merge(left, right):
result = []
left_index, right_index = 0, 0
while left_index < len(left) and right_index < len(right):
if left[left_index] < right[right_index]:
result.append(left[left_index])
left_index += 1
else:
result.append(right[right_index])
right_index += 1
result.extend(left[left_index:])
result.extend(right[right_index:])
return result
# Example usage
arr = [12, 11, 13, 5, 6, 7]
sorted_arr = merge_sort(arr)
print("Sorted array:", sorted_arr)
Code:
def generate_pascals_triangle(row, col):
if col == 0 or col == row:
return 1
else:
return generate_pascals_triangle(row - 1, col - 1) + generate_pascals_triangle(row - 1, col)
def print_pascals_triangle(n):
for row in range(n):
for col in range(row + 1):
print(generate_pascals_triangle(row, col), end=" ")
print()
# Example usage
num_rows = 5
print_pascals_triangle(num_rows)
Code:
def selection_sort_recursive(arr, index=0):
if index == len(arr) - 1:
return
min_index = index
for i in range(index + 1, len(arr)):
if arr[i] < arr[min_index]:
min_index = i
arr[index], arr[min_index] = arr[min_index], arr[index]
selection_sort_recursive(arr, index + 1)
# Example usage
arr = [64, 25, 12, 22, 11]
selection_sort_recursive(arr)
print("Sorted array:", arr)
Code:
def insertion_sort_recursive(arr, n):
if n <= 1:
return
insertion_sort_recursive(arr, n - 1)
key = arr[n - 1]
j = n - 2
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
# Example usage
arr = [12, 11, 13, 5, 6]
insertion_sort_recursive(arr, len(arr))
print("Sorted array:", arr)
Code:
def bubble_sort_recursive(arr, n):
if n == 1:
return
for i in range(n - 1):
if arr[i] > arr[i + 1]:
arr[i], arr[i + 1] = arr[i + 1], arr[i]
bubble_sort_recursive(arr, n - 1)
# Example usage
arr = [64, 34, 25, 12, 22, 11, 90]
bubble_sort_recursive(arr, len(arr))
print("Sorted array:", arr)
Harnessing recursion's power necessitates understanding its strengths and limitations.
Recursion, with its elegance and potency, stands as a robust tool in the arsenal of Python developers. While its advantages are manifold, judicious use is advised to avoid potential pitfalls. For professionals eager to venture beyond the foundational aspects and delve into advanced programming paradigms, upGrad provides a rich repository of courses. Harness the power of structured learning and elevate your coding journey.
1. How is the Fibonacci series using recursion in Python realized?
Implementing the Fibonacci series recursively involves each number being the sum of the two preceding ones, starting from 0 and 1.
2. Can you illustrate with a recursive function example?
A classic example is computing factorials. For instance, the factorial of 5 is 5 times the factorial of 4.
3. Why are there advantages and disadvantages of recursion in Python?
Like all tools, recursion has its strengths and weaknesses, making it essential to understand its best application scenarios.
4. What visualizes the stack diagram for recursive function in Python?
A stack diagram illustrates the sequence and hierarchy of recursive calls, showcasing how functions await the return of their subsequent calls.
5. Is tail recursion always superior to standard recursion?
Not always. Tail recursion is memory efficient, but its superiority hinges on the programming language and the specific problem at hand.
Take our Free Quiz on Python
Answer quick questions and assess your Python knowledge
Author
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918045604032
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.