Understanding Python Decorators: A Beginner’s Guide with Examples

Understanding Python Decorators: A Beginner’s Guide with Examples

Python decorators are a powerful and versatile tool for modifying the behavior of functions or methods. They allow you to add functionality to existing code without altering its structure. In this article, we’ll break down decorators and provide simple examples to help you understand and use them effectively.


What are Decorators?

A decorator in Python is essentially a function that takes another function as an argument and extends or alters its behavior. Decorators are commonly used to add features like logging, access control, memoization, or validation to existing functions or methods.

Decorators in Python are applied using the @decorator_name syntax placed above the function definition.


Anatomy of a Decorator

A basic decorator function has the following structure:

<span>def</span> <span>decorator_function</span><span>(</span><span>original_function</span><span>):</span>
<span>def</span> <span>wrapper_function</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>):</span>
<span># Code to execute before the original function </span> <span>result</span> <span>=</span> <span>original_function</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>)</span>
<span># Code to execute after the original function </span> <span>return</span> <span>result</span>
<span>return</span> <span>wrapper_function</span>
<span>def</span> <span>decorator_function</span><span>(</span><span>original_function</span><span>):</span>
    <span>def</span> <span>wrapper_function</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>):</span>
        <span># Code to execute before the original function </span>        <span>result</span> <span>=</span> <span>original_function</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>)</span>
        <span># Code to execute after the original function </span>        <span>return</span> <span>result</span>
    <span>return</span> <span>wrapper_function</span>
def decorator_function(original_function): def wrapper_function(*args, **kwargs): # Code to execute before the original function result = original_function(*args, **kwargs) # Code to execute after the original function return result return wrapper_function

Enter fullscreen mode Exit fullscreen mode

Applying a Decorator

You can apply a decorator to a function using the @decorator_name syntax or manually:

<span>@decorator_function</span>
<span>def</span> <span>some_function</span><span>():</span>
<span>print</span><span>(</span><span>"</span><span>This is the original function.</span><span>"</span><span>)</span>
<span># Equivalent to: # some_function = decorator_function(some_function) </span>
<span>@decorator_function</span>
<span>def</span> <span>some_function</span><span>():</span>
    <span>print</span><span>(</span><span>"</span><span>This is the original function.</span><span>"</span><span>)</span>

<span># Equivalent to: # some_function = decorator_function(some_function) </span>
@decorator_function def some_function(): print("This is the original function.") # Equivalent to: # some_function = decorator_function(some_function)

Enter fullscreen mode Exit fullscreen mode


Example 1: A Basic Decorator

Let’s create a simple decorator that prints a message before and after a function runs.

<span>def</span> <span>simple_decorator</span><span>(</span><span>func</span><span>):</span>
<span>def</span> <span>wrapper</span><span>():</span>
<span>print</span><span>(</span><span>"</span><span>Before the function call.</span><span>"</span><span>)</span>
<span>func</span><span>()</span>
<span>print</span><span>(</span><span>"</span><span>After the function call.</span><span>"</span><span>)</span>
<span>return</span> <span>wrapper</span>
<span>@simple_decorator</span>
<span>def</span> <span>say_hello</span><span>():</span>
<span>print</span><span>(</span><span>"</span><span>Hello, World!</span><span>"</span><span>)</span>
<span>say_hello</span><span>()</span>
<span>def</span> <span>simple_decorator</span><span>(</span><span>func</span><span>):</span>
    <span>def</span> <span>wrapper</span><span>():</span>
        <span>print</span><span>(</span><span>"</span><span>Before the function call.</span><span>"</span><span>)</span>
        <span>func</span><span>()</span>
        <span>print</span><span>(</span><span>"</span><span>After the function call.</span><span>"</span><span>)</span>
    <span>return</span> <span>wrapper</span>

<span>@simple_decorator</span>
<span>def</span> <span>say_hello</span><span>():</span>
    <span>print</span><span>(</span><span>"</span><span>Hello, World!</span><span>"</span><span>)</span>

<span>say_hello</span><span>()</span>
def simple_decorator(func): def wrapper(): print("Before the function call.") func() print("After the function call.") return wrapper @simple_decorator def say_hello(): print("Hello, World!") say_hello()

Enter fullscreen mode Exit fullscreen mode

Output:

Before the function call.
Hello, World!
After the function call.
Before the function call.
Hello, World!
After the function call.
Before the function call. Hello, World! After the function call.

Enter fullscreen mode Exit fullscreen mode


Example 2: A Decorator with Arguments

You can create a decorator that accepts arguments by wrapping it in another function.

<span>def</span> <span>repeat_decorator</span><span>(</span><span>times</span><span>):</span>
<span>def</span> <span>decorator</span><span>(</span><span>func</span><span>):</span>
<span>def</span> <span>wrapper</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>):</span>
<span>for</span> <span>_</span> <span>in</span> <span>range</span><span>(</span><span>times</span><span>):</span>
<span>func</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>)</span>
<span>return</span> <span>wrapper</span>
<span>return</span> <span>decorator</span>
<span>@repeat_decorator</span><span>(</span><span>3</span><span>)</span>
<span>def</span> <span>greet</span><span>(</span><span>name</span><span>):</span>
<span>print</span><span>(</span><span>f</span><span>"</span><span>Hello, </span><span>{</span><span>name</span><span>}</span><span>!</span><span>"</span><span>)</span>
<span>greet</span><span>(</span><span>"</span><span>Alice</span><span>"</span><span>)</span>
<span>def</span> <span>repeat_decorator</span><span>(</span><span>times</span><span>):</span>
    <span>def</span> <span>decorator</span><span>(</span><span>func</span><span>):</span>
        <span>def</span> <span>wrapper</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>):</span>
            <span>for</span> <span>_</span> <span>in</span> <span>range</span><span>(</span><span>times</span><span>):</span>
                <span>func</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>)</span>
        <span>return</span> <span>wrapper</span>
    <span>return</span> <span>decorator</span>

<span>@repeat_decorator</span><span>(</span><span>3</span><span>)</span>
<span>def</span> <span>greet</span><span>(</span><span>name</span><span>):</span>
    <span>print</span><span>(</span><span>f</span><span>"</span><span>Hello, </span><span>{</span><span>name</span><span>}</span><span>!</span><span>"</span><span>)</span>

<span>greet</span><span>(</span><span>"</span><span>Alice</span><span>"</span><span>)</span>
def repeat_decorator(times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(times): func(*args, **kwargs) return wrapper return decorator @repeat_decorator(3) def greet(name): print(f"Hello, {name}!") greet("Alice")

Enter fullscreen mode Exit fullscreen mode

Output:

Hello, Alice!
Hello, Alice!
Hello, Alice!
Hello, Alice!
Hello, Alice!
Hello, Alice!
Hello, Alice! Hello, Alice! Hello, Alice!

Enter fullscreen mode Exit fullscreen mode


Real-Life Applications of Decorators

Decorators are extensively used in real-world scenarios. Here are some simplified practical examples:

1. Logging User Actions

You can use a decorator to log every time a user performs an action.

<span>def</span> <span>log_action</span><span>(</span><span>func</span><span>):</span>
<span>def</span> <span>wrapper</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>):</span>
<span>print</span><span>(</span><span>f</span><span>"</span><span>Action: </span><span>{</span><span>func</span><span>.</span><span>__name__</span><span>}</span><span> is being performed.</span><span>"</span><span>)</span>
<span>return</span> <span>func</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>)</span>
<span>return</span> <span>wrapper</span>
<span>@log_action</span>
<span>def</span> <span>upload_file</span><span>(</span><span>filename</span><span>):</span>
<span>print</span><span>(</span><span>f</span><span>"</span><span>Uploading </span><span>{</span><span>filename</span><span>}</span><span>...</span><span>"</span><span>)</span>
<span>upload_file</span><span>(</span><span>"</span><span>report.pdf</span><span>"</span><span>)</span>
<span>def</span> <span>log_action</span><span>(</span><span>func</span><span>):</span>
    <span>def</span> <span>wrapper</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>):</span>
        <span>print</span><span>(</span><span>f</span><span>"</span><span>Action: </span><span>{</span><span>func</span><span>.</span><span>__name__</span><span>}</span><span> is being performed.</span><span>"</span><span>)</span>
        <span>return</span> <span>func</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>)</span>
    <span>return</span> <span>wrapper</span>

<span>@log_action</span>
<span>def</span> <span>upload_file</span><span>(</span><span>filename</span><span>):</span>
    <span>print</span><span>(</span><span>f</span><span>"</span><span>Uploading </span><span>{</span><span>filename</span><span>}</span><span>...</span><span>"</span><span>)</span>

<span>upload_file</span><span>(</span><span>"</span><span>report.pdf</span><span>"</span><span>)</span>
def log_action(func): def wrapper(*args, **kwargs): print(f"Action: {func.__name__} is being performed.") return func(*args, **kwargs) return wrapper @log_action def upload_file(filename): print(f"Uploading {filename}...") upload_file("report.pdf")

Enter fullscreen mode Exit fullscreen mode

Output:

Action: upload_file is being performed.
Uploading report.pdf...
Action: upload_file is being performed.
Uploading report.pdf...
Action: upload_file is being performed. Uploading report.pdf...

Enter fullscreen mode Exit fullscreen mode


2. Tracking Execution Time

Track how long tasks take to execute, useful for performance monitoring.

<span>import</span> <span>time</span>
<span>def</span> <span>track_time</span><span>(</span><span>func</span><span>):</span>
<span>def</span> <span>wrapper</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>):</span>
<span>start</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span>
<span>result</span> <span>=</span> <span>func</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>)</span>
<span>end</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span>
<span>print</span><span>(</span><span>f</span><span>"</span><span>{</span><span>func</span><span>.</span><span>__name__</span><span>}</span><span> took </span><span>{</span><span>end</span> <span>-</span> <span>start</span><span>:</span><span>.</span><span>2</span><span>f</span><span>}</span><span> seconds to execute.</span><span>"</span><span>)</span>
<span>return</span> <span>result</span>
<span>return</span> <span>wrapper</span>
<span>@track_time</span>
<span>def</span> <span>download_file</span><span>(</span><span>file_size</span><span>):</span>
<span>time</span><span>.</span><span>sleep</span><span>(</span><span>file_size</span> <span>/</span> <span>10</span><span>)</span> <span># Simulate download time </span> <span>print</span><span>(</span><span>"</span><span>Download complete.</span><span>"</span><span>)</span>
<span>download_file</span><span>(</span><span>50</span><span>)</span>
<span>import</span> <span>time</span>

<span>def</span> <span>track_time</span><span>(</span><span>func</span><span>):</span>
    <span>def</span> <span>wrapper</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>):</span>
        <span>start</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span>
        <span>result</span> <span>=</span> <span>func</span><span>(</span><span>*</span><span>args</span><span>,</span> <span>**</span><span>kwargs</span><span>)</span>
        <span>end</span> <span>=</span> <span>time</span><span>.</span><span>time</span><span>()</span>
        <span>print</span><span>(</span><span>f</span><span>"</span><span>{</span><span>func</span><span>.</span><span>__name__</span><span>}</span><span> took </span><span>{</span><span>end</span> <span>-</span> <span>start</span><span>:</span><span>.</span><span>2</span><span>f</span><span>}</span><span> seconds to execute.</span><span>"</span><span>)</span>
        <span>return</span> <span>result</span>
    <span>return</span> <span>wrapper</span>

<span>@track_time</span>
<span>def</span> <span>download_file</span><span>(</span><span>file_size</span><span>):</span>
    <span>time</span><span>.</span><span>sleep</span><span>(</span><span>file_size</span> <span>/</span> <span>10</span><span>)</span>  <span># Simulate download time </span>    <span>print</span><span>(</span><span>"</span><span>Download complete.</span><span>"</span><span>)</span>

<span>download_file</span><span>(</span><span>50</span><span>)</span>
import time def track_time(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(f"{func.__name__} took {end - start:.2f} seconds to execute.") return result return wrapper @track_time def download_file(file_size): time.sleep(file_size / 10) # Simulate download time print("Download complete.") download_file(50)

Enter fullscreen mode Exit fullscreen mode

Output:

Download complete.
download_file took 5.00 seconds to execute.
Download complete.
download_file took 5.00 seconds to execute.
Download complete. download_file took 5.00 seconds to execute.

Enter fullscreen mode Exit fullscreen mode


3. Adding User Greetings

A decorator can personalize greetings by adding dynamic elements.

<span>def</span> <span>add_greeting</span><span>(</span><span>func</span><span>):</span>
<span>def</span> <span>wrapper</span><span>(</span><span>name</span><span>):</span>
<span>print</span><span>(</span><span>"</span><span>Hello, welcome!</span><span>"</span><span>)</span>
<span>func</span><span>(</span><span>name</span><span>)</span>
<span>return</span> <span>wrapper</span>
<span>@add_greeting</span>
<span>def</span> <span>show_user_profile</span><span>(</span><span>name</span><span>):</span>
<span>print</span><span>(</span><span>f</span><span>"</span><span>User Profile: </span><span>{</span><span>name</span><span>}</span><span>"</span><span>)</span>
<span>show_user_profile</span><span>(</span><span>"</span><span>Alice</span><span>"</span><span>)</span>
<span>def</span> <span>add_greeting</span><span>(</span><span>func</span><span>):</span>
    <span>def</span> <span>wrapper</span><span>(</span><span>name</span><span>):</span>
        <span>print</span><span>(</span><span>"</span><span>Hello, welcome!</span><span>"</span><span>)</span>
        <span>func</span><span>(</span><span>name</span><span>)</span>
    <span>return</span> <span>wrapper</span>

<span>@add_greeting</span>
<span>def</span> <span>show_user_profile</span><span>(</span><span>name</span><span>):</span>
    <span>print</span><span>(</span><span>f</span><span>"</span><span>User Profile: </span><span>{</span><span>name</span><span>}</span><span>"</span><span>)</span>

<span>show_user_profile</span><span>(</span><span>"</span><span>Alice</span><span>"</span><span>)</span>
def add_greeting(func): def wrapper(name): print("Hello, welcome!") func(name) return wrapper @add_greeting def show_user_profile(name): print(f"User Profile: {name}") show_user_profile("Alice")

Enter fullscreen mode Exit fullscreen mode

Output:

Hello, welcome!
User Profile: Alice
Hello, welcome!
User Profile: Alice
Hello, welcome! User Profile: Alice

Enter fullscreen mode Exit fullscreen mode


Key Takeaways

  • Decorators are a powerful way to modify the behavior of functions or methods.
  • They can simplify repetitive tasks like logging, timing, or personalization.
  • Use the @decorator syntax to apply them conveniently.
  • Decorators can accept arguments and be nested for added flexibility.

By mastering decorators, you’ll unlock a valuable tool for writing clean and efficient Python code. Start experimenting with the examples provided to get comfortable with this concept!

原文链接:Understanding Python Decorators: A Beginner’s Guide with Examples

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
The reason why a great man is great is that he resolves to be a great man.
伟人之所以伟大,是因为他立志要成为伟大的人
评论 抢沙发

请登录后发表评论

    暂无评论内容