BACSE101
Problem Solving Using Python
Decorators and Recursive Functions
Decorators
Decorators in Python are a design pattern that allows you to dynamically modify the functionality of a function
or class without changing its source code.
They are represented by the @ symbol followed by the decorator function's name and are placed immediately
before the function or class definition you want to decorate.
A decorator is essentially a higher-order function that takes another function as an argument, adds some new
functionality, and then returns the modified function.
Example This is the decorator function. It takes another function, func, as an argument. In this specific case, func will be say_hello.
This is a nested function defined inside my_decorator. It's the core of the decorator's functionality.
This function contains the new behavior you want to add, which is printing a message "before" and
"after" the original function is executed. The line func() is what actually calls the original say_hello
# The decorator function function, ensuring its original behavior is preserved.
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
The my_decorator function returns the wrapper function.
return wrapper It doesn't call wrapper(), it just returns a reference to it.
This is the decorator syntax. It's a syntactic shortcut for what is happening
# The function to be decorated behind the scenes: say_hello = my_decorator(say_hello). Python automatically
@my_decorator passes the say_hello function to my_decorator, which then returns the
shorthand for say_hello = my_decorator(say_hello) wrapper function. The original say_hello is effectively replaced by this new,
Def say_hello(): decorated wrapper function.
print("Hello, World!")
# Calling the decorated function
When you call say_hello() at the end, you're no longer calling the original function. You're calling the wrapper
say_hello() function that was returned by my_decorator.
Key Uses of Decorators
Decorators are widely used in Python frameworks and libraries for various purposes:
•Logging and debugging: To automatically log function calls and their arguments.
•Performance measurement: To time how long a function takes to execute.
•Authentication and authorization: To check if a user has the right permissions to access a certain
function.
•Caching: To store the results of expensive function calls to avoid re-computation.
•API routing: In web frameworks like Flask and Django, decorators are used to map a URL to a
specific function, for example, @[Link]('/about').
Recursive Functions
A recursive function in Python is a function that calls itself during its execution. This technique is used to solve problems that
can be broken down into smaller, similar subproblems.
Key Components of a Recursive Function:
Base Case:
This is a condition that stops the recursion. When the base case is met, the function returns a value without
making further recursive calls, preventing infinite recursion.
Recursive Case:
This is the part of the function where it calls itself with a modified input, moving closer to the base case.
Example: For n=0 For n=1
def factorial(n):
# Base Case
if n == 0 or n == 1:
return 1
# Recursive Case
else:
return n * factorial(n - 1)
print(factorial(5))
For n=5
Advantages and Disadvantages
Advantages:
•Code readability: Recursive solutions can often be more intuitive and easier to read for problems that have a
natural recursive structure (e.g., tree traversals, searching algorithms).
•Elegance: It can lead to cleaner, more concise code compared to an iterative solution with loops.
Disadvantages:
•Performance: Recursive functions can be slower than their iterative counterparts due to the overhead of
function calls.
•Memory usage: Each function call is added to the call stack. If the recursion is too deep, it can lead to a
RecursionError and consume a large amount of memory. Python has a default recursion limit (usually 1000) to
prevent this.