首頁  >  文章  >  後端開發  >  掌握 Python 中的閉包與裝飾器:從基礎到高級

掌握 Python 中的閉包與裝飾器:從基礎到高級

DDD
DDD原創
2024-09-19 01:39:33584瀏覽

Mastering Closures and Decorators in Python: From Basics to Advanced

介紹

閉包和裝飾器是 Python 中強大的功能,可讓您編寫更靈活和可重複使用的程式碼。理解這些概念將使您的 Python 技能更上一層樓,讓您輕鬆處理更複雜的場景,例如日誌記錄、存取控制和記憶。

在這篇文章中,我們將探討:

  1. 什麼是閉包?
  2. 了解 Python 中閉包的工作原理
  3. 閉包的用例
  4. 什麼是裝飾器?
  5. 了解裝飾器如何運作
  6. 使用內建裝飾器
  7. 編寫自訂裝飾器
  8. 裝飾器的高級概念

讀完本文,您將牢牢掌握閉包和裝飾器,並且能夠在自己的程式碼中有效地應用它們。

什麼是閉包?

在 Python 中,閉包 是保留其封閉詞法範圍內的變數值的函數,即使外部函數已完成執行也是如此。閉包是一種在函數呼叫之間保留狀態的方法,這使得它們對於需要維護某些上下文的場景非常有用。

閉包由三個主要組件組成:

  1. 巢狀函數
  2. 封閉函數中自由變數的引用
  3. 封閉函數已執行完畢,但巢狀函數仍然記得自由變數的狀態。

閉包的基本範例

這是一個簡單閉包的範例:

def outer_function(message):
    def inner_function():
        print(message)
    return inner_function

# Create a closure
closure = outer_function("Hello, World!")
closure()  # Output: Hello, World!

在此範例中,inner_function 引用來自outer_function 的訊息變量,即使outer_function 已完成執行也是如此。內部函數從外部作用域「關閉」變量,因此術語 closure.

閉包在內部如何運作

閉包透過捕捉自由變數的狀態並將它們儲存在函數物件的 __closure__ 屬性中來運作。

讓我們檢查上一個範例中的閉包:

print(closure.__closure__[0].cell_contents)  # Output: Hello, World!

__closure__ 屬性保存對閉包保留的變數的參考。每個變數都儲存在一個「儲存格」中,您可以使用 cell_contents 存取其內容。

閉包的用例

當您想要在不使用全域變數或類別的情況下維護函數呼叫之間的狀態時,閉包特別有用。以下是一些常見用例:

1. 函數工廠

您可以使用閉包動態建立函數。

def multiplier(factor):
    def multiply_by_factor(number):
        return number * factor
    return multiply_by_factor

times_two = multiplier(2)
times_three = multiplier(3)

print(times_two(5))  # Output: 10
print(times_three(5))  # Output: 15

在此範例中,multiplier 傳回一個將給定數字乘以特定因子的函數。閉包 times_two 和 times_third 保留其封閉範圍內因子的值。

2. 封裝

閉包可讓您封裝行為而不暴露內部狀態。這類似於物件導向程式設計中私有方法的概念。

def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

counter_fn = counter()
print(counter_fn())  # Output: 1
print(counter_fn())  # Output: 2

在這個例子中,count變數被封裝在閉包內,只有increment函數可以修改它的值。

什麼是裝飾器?

裝飾器是一個函數,它接受另一個函數並擴展或改變其行為,而不修改原始函數的程式碼。裝飾器通常用於向函數和方法添加日誌記錄、存取控製或計時等功能。

在 Python 中,裝飾器透過函數定義上方的 @ 符號應用於函數。

裝飾器的基本範例

def decorator_function(original_function):
    def wrapper_function():
        print(f"Wrapper executed before {original_function.__name__}()")
        return original_function()
    return wrapper_function

@decorator_function
def say_hello():
    print("Hello!")

say_hello()

# Output:
# Wrapper executed before say_hello()
# Hello!

這裡,decorator_function 應用於 say_hello,在 say_hello() 執行之前加入額外的功能。

裝飾器如何運作

裝飾器本質上是 Python 中常見模式的語法糖:高階函數,它接受其他函數作為參數。當你寫@decorator時,就相當於:

say_hello = decorator_function(say_hello)

裝飾器函數傳回一個新函數(wrapper_function),它擴展了原始函數的行為。

帶參數的裝飾器

如果被修飾的函式接受參數,則包裝函式需要接受 *args 和 **kwargs 來傳遞參數。

def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        print(f"Wrapper executed before {original_function.__name__}()")
        return original_function(*args, **kwargs)
    return wrapper_function

@decorator_function
def display_info(name, age):
    print(f"display_info ran with arguments ({name}, {age})")

display_info("John", 25)

# Output:
# Wrapper executed before display_info()
# display_info ran with arguments (John, 25)

Python 中的內建裝飾器

Python提供了一些內建的裝飾器,例如@staticmethod、@classmethod和@property。

@staticmethod and @classmethod

These decorators are commonly used in object-oriented programming to define methods that are either not bound to the instance (@staticmethod) or bound to the class itself (@classmethod).

class MyClass:
    @staticmethod
    def static_method():
        print("Static method called")

    @classmethod
    def class_method(cls):
        print(f"Class method called from {cls}")

MyClass.static_method()   # Output: Static method called
MyClass.class_method()    # Output: Class method called from <class '__main__.MyClass'>

@property

The @property decorator allows you to define a method that can be accessed like an attribute.

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value <= 0:
            raise ValueError("Radius must be positive")
        self._radius = value

c = Circle(5)
print(c.radius)  # Output: 5

c.radius = 10
print(c.radius)  # Output: 10

Writing Custom Decorators

You can write your own decorators to add custom functionality to your functions or methods. Decorators can be stacked, meaning you can apply multiple decorators to a single function.

Example: Timing a Function

Here’s a custom decorator that measures the execution time of a function:

import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} ran in {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timer_decorator
def calculate_square(numbers):
    result = [n * n for n in numbers]
    return result

nums = range(1, 1000000)
calculate_square(nums)

Decorators with Arguments

Decorators can also accept their own arguments. This is useful when you need to pass configuration values to the decorator.

Example: Logger with Custom Message

def logger_decorator(message):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"{message}: Executing {func.__name__}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@logger_decorator("DEBUG")
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

# Output:
# DEBUG: Executing greet
# Hello, Alice!

In this example, the decorator logger_decorator takes a message as an argument, and then it wraps the greet function with additional logging functionality.

Advanced Decorator Concepts

1. Decorating Classes

Decorators can be applied not only to functions but also to classes. Class decorators modify or extend the behavior of entire classes.

def add_str_repr(cls):
    cls.__str__ = lambda self: f"Instance of {cls.__name__}"
    return cls

@add_str_repr
class Dog:
    pass

dog = Dog()
print(dog)  # Output: Instance of Dog

2. Memoization with Decorators

Memoization is an optimization technique where the results of expensive function calls are cached, so subsequent calls with the same arguments can be returned faster.

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

@memoize
def fibonacci(n):


 if n in [0, 1]:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(30))  # Output: 832040

Conclusion

Closures and decorators are advanced Python concepts that unlock powerful capabilities for writing cleaner, more efficient code. Closures allow you to maintain state and encapsulate data, while decorators let you modify or extend the behavior of functions and methods in a reusable way. Whether you're optimizing performance with memoization, implementing access control, or adding logging, decorators are an essential tool in your Python toolkit.

By mastering these concepts, you'll be able to write more concise and maintainable code and handle complex programming tasks with ease.

Feel free to experiment with closures and decorators in your projects and discover how they can make your code more elegant and powerful!


Connect with Me

  • GitHub
  • Linkedin

以上是掌握 Python 中的閉包與裝飾器:從基礎到高級的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn