1
Current Location:
>
Function Decorators
The Wonderful World of Decorators
Release time:2024-10-15 08:07:06 read 19
Copyright Statement: This article is an original work of the website and follows the CC 4.0 BY-SA copyright agreement. Please include the original source link and this statement when reprinting.

Article link: https://60235.com/en/content/aid/541?s=en%2Fcontent%2Faid%2F541

Hi, folks! Today we're going to talk about those magical decorators in Python. They're not just minor players in your code, but entities that can give your functions brand new "superpowers"! Let's explore their mysteries.

What are decorators?

First, let's unravel the mystery in your mind. A decorator is essentially a function that can add new behaviors to the original function without modifying its code. Sounds cool, right? It's like putting a new coat on your function!

Here's a simple example. Let's say you have an addition function like this:

def add(a, b):
    return a + b

If we want to print a line of output when calling this function, how do we do it? You might think of directly modifying the function body, but that's not very elegant. This is where decorators can make a grand entrance:

def print_result(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(f"Result: {result}")
        return result
    return wrapper

@print_result
def add(a, b):
    return a + b

add(2, 3) # Outputs "Result: 5"

Look, we've "decorated" the add function with a print_result function, adding the new functionality of printing the result without touching the original function code! Isn't that cool?

Application Scenarios

Decorators can be used in various situations, such as:

Access Control

def admin_only(func):
    def wrapper(*args, **kwargs):
        user = get_current_user()
        if user.is_admin():
            return func(*args, **kwargs)
        else:
            raise PermissionError("You're not an admin!")
    return wrapper

@admin_only
def reset_password(user_id):
    ...

With the admin_only decorator, we can ensure that only administrators can reset user passwords.

Caching Optimization

cache = {}

def memoize(func):
    def wrapper(*args):
        if args in cache:
            return cache[args]
        result = func(*args)
        cache[args] = result
        return result
    return wrapper

@memoize
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

Through the memoize decorator, we can cache expensive fibonacci calculation results, returning the cached value directly next time, greatly improving performance!

Logging

import logging

def log(func):
    def wrapper(*args, **kwargs):
        logging.info(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
        result = func(*args, **kwargs)
        logging.info(f"{func.__name__} returned {result}")
        return result
    return wrapper

@log
def add(a, b):
    return a + b

Yes, logging can also be implemented through decorators, saying goodbye to repetitive logging.info calls!

Advanced Techniques

If you already have some understanding of decorators, let's look at some more advanced uses.

Decorators with Parameters

Sometimes we want the decorator itself to accept parameters, for example:

def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hello(name):
    print(f"Hello {name}")

say_hello("Bob") # Outputs "Hello Bob" three times

Through this nested approach, we can create a decorator that can accept parameters.

Decorator Classes

Sometimes, implementing decorators as classes can be more readable and maintainable. Let's feel it with a timer example:

import time

class TimerDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start = time.perf_counter()
        result = self.func(*args, **kwargs)
        end = time.perf_counter()
        print(f"{self.func.__name__} took {end - start:.6f} seconds")
        return result

@TimerDecorator
def factorial(n):
    result = 1
    for i in range(1, n+1):
        result *= i
    return result

factorial(100000)

Through the __call__ method, we can use this decorator class just like calling a regular function.

Summary

Today we've explored various wonderful uses of decorators, and I believe you now have a deeper understanding of them. They not only elegantly extend existing functions but also make our code more concise and readable. Of course, the magic of decorators goes far beyond this; they are also indispensable tools in areas such as web frameworks and testing tools.

So, which use of decorators do you like the most? Or do you have more clever decorator techniques to share with us? Either way, let's continue to explore the endless charm of Python together! Coding has never been so extraordinary!

Python Decorators: Making Your Code More Elegant and Powerful
2024-11-07 12:07:02
Next
Related articles