So far, our decorators only worked with functions that had no parameters. In real life, most functions take arguments. Let’s see how decorators handle them.
1) Why Arguments Matter?
If your decorated function accepts parameters, the wrapper inside the decorator must also be able to accept them. Otherwise, you’ll get an error like:
TypeError: wrapper_function() takes 0 positional arguments but 2 were given
2) Solution: Using *args and **kwargs
By using *args and **kwargs, your wrapper can accept any number of positional and keyword arguments,
making the decorator flexible for all functions.
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
print("Before execution")
result = original_function(*args, **kwargs) # Pass arguments
print("After execution")
return result
return wrapper_function
@decorator_function
def greet(name, age):
print(f"Hello {name}, you are {age} years old!")
greet("Alice", 25)
Output:
Before execution
Hello Alice, you are 25 years old!
After execution
3) Decorator with Its Own Arguments
Sometimes we want to pass arguments to the decorator itself. To achieve this, we wrap the decorator inside another function.
def repeat(num_times):
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
for _ in range(num_times):
original_function(*args, **kwargs)
return wrapper_function
return decorator_function
@repeat(3)
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Bob")
Output:
Hello, Bob!
Hello, Bob!
Hello, Bob!
4) Common Mistakes
- Forgetting *args and **kwargs → your decorator will fail on functions with parameters.
- Returning None instead of result → always return the value of the original function if it has one.
- Overusing decorator arguments → too much nesting makes code harder to read.
No comments:
Post a Comment