通过八个 Python 装饰器理解高阶函数

开发
装饰器可以让我们在不修改原始函数代码的情况下,增加额外的功能。比如记录日志、计时、缓存等。这样不仅让代码更简洁,也更容易维护。

1. 什么是高阶函数?

高阶函数是指至少满足以下条件之一的函数:

  • 接受一个或多个函数作为参数。
  • 返回一个函数。

装饰器就是一种特殊的高阶函数,用来修改其他函数的行为。

2. 为什么使用装饰器?

装饰器可以让我们在不修改原始函数代码的情况下,增加额外的功能。比如记录日志、计时、缓存等。这样不仅让代码更简洁,也更容易维护。

3. 装饰器的基本语法

装饰器本质上是一个接受函数作为参数的函数,并返回一个新的函数。下面是一个简单的装饰器示例。

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

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

say_hello()

输出:

Something is happening before the function is called.
Hello!
Something is happening after the function is called.

4. 实战案例六:参数验证装饰器

参数验证装饰器可以在执行函数之前验证传入参数的有效性。

def validate_params(*param_types):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if len(args) != len(param_types):
                raise ValueError("Incorrect number of arguments")

            for arg, param_type in zip(args, param_types):
                if not isinstance(arg, param_type):
                    raise TypeError(f"Argument {arg} is not of type {param_type.__name__}")

            return func(*args, **kwargs)
        return wrapper
    return decorator

@validate_params(int, int)
def multiply(x, y):
    return x * y

print(multiply(3, 4))  # 正确
# print(multiply(3, "hello"))  # 抛出 TypeError

输出:

12

这个装饰器会检查传入的参数类型是否符合预期。如果不符合,会抛出相应的异常。

5. 实战案例七:限制调用次数装饰器

限制调用次数装饰器可以在一定时间内限制函数的调用次数。

import time

def limit_calls(max_calls, period):
    def decorator(func):
        call_times = []

        def wrapper(*args, **kwargs):
            current_time = time.time()
            call_times.append(current_time)
            while call_times and call_times[0] < current_time - period:
                call_times.pop(0)

            if len(call_times) > max_calls:
                raise Exception("Too many calls in a short period of time")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@limit_calls(max_calls=2, period=5)
def process_request(data):
    print(f"Processing request: {data}")

process_request("data1")
time.sleep(1)
process_request("data2")
time.sleep(1)
process_request("data3")  # 抛出 Exception

输出:

Processing request: data1
Processing request: data2
Too many calls in a short period of time

这个装饰器限制了 process_request 函数在 5 秒内只能被调用两次。如果超过这个限制,会抛出异常。

6. 实战案例八:缓存装饰器(自定义)

自定义缓存装饰器可以根据特定需求实现缓存功能。

from functools import wraps

def custom_cache(func):
    cache = {}

    @wraps(func)
    def wrapper(*args, **kwargs):
        key = (args, frozenset(kwargs.items()))
        if key not in cache:
            cache[key] = func(*args, **kwargs)
        return cache[key]

    return wrapper

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

for i in range(10):
    print(fibonacci(i))

输出:

0
1
1
2
3
5
8
13
21
34

这个装饰器使用了一个字典 cache 来存储函数的计算结果。如果相同的参数再次传入,就直接从缓存中获取结果。

7. 实战案例九:异步装饰器

异步装饰器可以让函数异步执行,提高程序的响应速度。

import asyncio

async def async_decorator(func):
    async def wrapper(*args, **kwargs):
        return await func(*args, **kwargs)
    return wrapper

@async_decorator
async def download_file(url):
    print(f"Downloading file from {url}")
    await asyncio.sleep(2)  # 模拟下载过程
    print(f"File downloaded from {url}")

async def main():
    await asyncio.gather(
        download_file("http://example.com/file1"),
        download_file("http://example.com/file2")
    )

asyncio.run(main())

输出:

Downloading file from http://example.com/file1
Downloading file from http://example.com/file2
File downloaded from http://example.com/file1
File downloaded from http://example.com/file2

这个装饰器将函数转换为异步函数,并允许并行执行多个任务。

8. 实战案例十:多线程装饰器

多线程装饰器可以让函数在多个线程中并发执行。

import threading

def thread_decorator(func):
    def wrapper(*args, **kwargs):
        thread = threading.Thread(target=func, args=args, kwargs=kwargs)
        thread.start()
        return thread
    return wrapper

@thread_decorator
def print_message(message):
    print(message)

print_message("Hello, world!")
print_message("Goodbye, world!")

# 等待所有线程完成
for thread in threading.enumerate():
    if thread != threading.current_thread():
        thread.join()

输出(顺序可能不同):

Hello, world!
Goodbye, world!

这个装饰器将函数放在不同的线程中执行,并等待所有线程完成。

责任编辑:赵宁宁 来源: 小白PythonAI编程
相关推荐

2024-09-12 15:32:35

装饰器Python

2024-03-08 08:00:00

Python开发装饰器

2022-09-21 13:32:39

Python装饰器

2024-05-21 10:40:09

开发前端装饰器

2022-02-11 09:00:00

技术债务数据工具

2022-09-19 23:04:08

Python装饰器语言

2024-08-27 12:18:23

函数Python

2010-02-01 17:50:32

Python装饰器

2023-02-07 07:47:52

Python装饰器函数

2024-07-18 15:08:27

2024-05-13 18:33:08

SQL日期函数

2021-06-01 07:19:58

Python函数装饰器

2018-10-08 08:42:06

编程语言DjangoPython

2010-11-09 14:18:41

2009-12-03 17:18:19

软件路由器功能

2024-11-11 06:10:00

Python生成器迭代器

2022-01-11 14:47:48

人工智能工程挖掘自动化流程发现

2024-06-26 13:11:40

2017-07-07 17:01:32

装饰器代码Python

2023-01-11 11:35:40

重构PythonPythonic
点赞
收藏

51CTO技术栈公众号