杰瑞科技汇

Python函数中的@符号是什么意思?

Of course! The symbol in Python is used for decorator syntax.

A decorator is a powerful and elegant feature that allows you to modify or extend the behavior of a function or class method without permanently modifying its source code. Think of it as "wrapping" a function with additional functionality.


The Core Concept: Functions as First-Class Citizens

To understand decorators, you first need to know that in Python, functions are first-class objects. This means:

  • You can assign a function to a variable.
  • You can pass a function as an argument to another function.
  • You can return a function from another function.

This last point is the key to how decorators work.


A Simple Example Without Decorators

Imagine you want to add logging to a function every time it's called. Without a decorator, you might do this:

def add(a, b):
    print(f"Function 'add' is being called with args: {a}, {b}")
    return a + b
# Using the function
result = add(5, 3)
print(f"Result: {result}")
# Output:
# Function 'add' is being called with args: 5, 3
# Result: 8

This works, but what if you have 20 functions and you want to add logging to all of them? You'd have to copy-paste the print statement into every single function. This is repetitive and not maintainable.


How Decorators Work: The Manual Way

A decorator is a function that takes another function as an argument, adds some functionality, and returns a new function.

Let's create a my_decorator function that does the logging for us.

def my_decorator(func):
    """This is the decorator function."""
    def wrapper():
        """This is the 'wrapper' function that replaces the original."""
        print(f"Something is happening before the function '{func.__name__}' is called.")
        result = func()  # Call the original function
        print(f"Something is happening after the function '{func.__name__}' is called.")
        return result
    return wrapper
def say_hello():
    print("Hello!")
# Now, let's apply our decorator
say_hello = my_decorator(say_hello)
# Call the decorated function
say_hello()
# Output:
# Something is happening before the function 'say_hello' is called.
# Hello!
# Something is happening after the function 'say_hello' is called.

What happened here?

  1. We defined my_decorator, which takes a function func as an argument.
  2. Inside my_decorator, we defined a wrapper function. This wrapper contains the extra code we want to run (the print statements).
  3. The wrapper function calls the original func() and returns its result.
  4. my_decorator returns this wrapper function.
  5. The line say_hello = my_decorator(say_hello) is crucial. It re-assigns the say_hello variable to be the wrapper function returned by my_decorator. So, when you call say_hello(), you are actually calling wrapper().

The Syntax (The "Syntactic Sugar")

The manual way works, but it's a bit clunky. Python provides a cleaner, more readable syntax using the symbol. This is called "syntactic sugar" because it makes the code sweeter.

The following two code blocks are functionally identical:

Without :

def my_decorator(func):
    def wrapper():
        print("Before...")
        func()
        print("After...")
    return wrapper
def say_hello():
    print("Hello!")
say_hello = my_decorator(say_hello)

With :

def my_decorator(func):
    def wrapper():
        print("Before...")
        func()
        print("After...")
    return wrapper
@my_decorator
def say_hello():
    print("Hello!")
# Now you can just call the function directly
say_hello()

The @my_decorator line above the function definition is a shortcut that tells Python: "Instead of calling say_hello = my_decorator(say_hello), do it automatically."


Practical Examples

Example 1: Timing Function Execution

This is a very common use case. Let's create a decorator that measures how long a function takes to run.

import time
def timer_decorator(func):
    def wrapper(*args, **kwargs): # *args and **kwargs make the decorator flexible
        start_time = time.time()
        result = func(*args, **kwargs) # Pass original arguments
        end_time = time.time()
        print(f"Function '{func.__name__}' executed in {end_time - start_time:.4f} seconds")
        return result
    return wrapper
@timer_decorator
def slow_function(seconds):
    print(f"Sleeping for {seconds} seconds...")
    time.sleep(seconds)
slow_function(2)
# Output:
# Sleeping for 2 seconds...
# Function 'slow_function' executed in 2.0021 seconds

Note: We used `argsand*kwargsto allow thewrapper` to accept any number of positional and keyword arguments, making our decorator much more reusable.

Example 2: Checking User Permissions

You can use decorators to enforce access control.

def admin_required(func):
    def wrapper(user, *args, **kwargs):
        if user.get('role') != 'admin':
            print("Access Denied: Admins only.")
            return
        return func(user, *args, **kwargs)
    return wrapper
@admin_required
def delete_user(user, username_to_delete):
    print(f"Admin '{user['name']}' is deleting user '{username_to_delete}'.")
# --- Usage ---
current_user = {'name': 'Alice', 'role': 'admin'}
delete_user(current_user, 'Bob') # Works
regular_user = {'name': 'Charlie', 'role': 'user'}
delete_user(regular_user, 'Dave') # Blocked
# Output:
# Admin 'Alice' is deleting user 'Bob'.
# Access Denied: Admins only.

Decorators with Arguments

What if you want to pass arguments to the decorator itself? For example, a repeat decorator that repeats a function a certain number of times.

To do this, you need one more level of function nesting.

def repeat(num_times):
    """A decorator factory that takes an argument."""
    def decorator_repeat(func):
        """The actual decorator."""
        def wrapper(*args, **kwargs):
            """The wrapper function."""
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator_repeat
@repeat(num_times=3)
def greet(name):
    print(f"Hello, {name}!")
greet("World")
# Output:
# Hello, World!
# Hello, World!
# Hello, World!

Here, repeat is a decorator factory. It's a function that returns a decorator. The @repeat(num_times=3) syntax first calls repeat(num_times=3), which returns the decorator_repeat function, which is then applied to greet.


Summary

Concept Description Example
Decorator A function that modifies another function. @timer
Wrapper The inner function in a decorator that contains the extra logic. def wrapper(): ...
Syntax Syntactic sugar for applying a decorator. Makes code cleaner. @my_decorator
*`args, kwargs` Used in a wrapper to accept any arguments, making the decorator flexible. def wrapper(*args, **kwargs): ...
Decorator Factory A function that returns a decorator, allowing you to pass arguments to the decorator. @repeat(num_times=3)

Decorators are a cornerstone of modern Python programming, used extensively in web frameworks (like Flask and Django for routing), logging, testing, and many other areas.

分享:
扫描分享到社交APP
上一篇
下一篇