欢迎访问宙启技术站
智能推送

在Python函数中使用装饰器实现函数扩展

发布时间:2023-06-03 04:52:41

Python装饰器是一种很有用的编程技巧,可以在不改变原函数的代码的情况下,添加或修改其功能。装饰器可以用于函数、类、方法等对象上,本文将着重介绍在Python函数中使用装饰器实现扩展的方法。

一、什么是装饰器

装饰器(Decorator)是 Python 语言中的一种特殊语法,它可以在代码运行期间动态地修改函数或类。装饰器常用于扩展函数的功能,例如:添加日志、鉴权、计时等操作,而不需要修改原函数的代码。

装饰器本质上是一个 Python 函数或类,它接受一个函数或类作为参数,并返回一个新的函数或类。使用装饰器时,需要在原函数的定义上面添加 @decorator_name,这样 Python 解释器就会自动执行装饰器函数,并将原函数作为参数传递进去,最终返回一个新函数作为原函数的代理对象。

下面是一个简单的装饰器示例:

def my_decorator(func):
    def wrapper():
        print("Start.")
        func()
        print("End.")
    return wrapper

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

say_hello()

代码说明:

定义了一个装饰器函数 my_decorator,它接受一个函数作为参数,并返回一个新函数 wrapper。

新函数 wrapper 在原函数执行前后添加了一些额外的操作,打印了“Start.”和“End.”。

在原函数 say_hello 上方添加了装饰器 @my_decorator,实际上是将其传递给 my_decorator 函数,返回一个新函数作为 say_hello 的代理对象。

最终,执行 say_hello() 时,实际上执行的是新函数 wrapper。输出结果为:

Start.
Hello!
End.

二、装饰器类型

根据装饰器的参数类型和返回类型,可以将装饰器分为函数装饰器和类装饰器。函数装饰器是最常见的一种,它接受一个函数作为参数,并返回一个新函数;类装饰器则接受一个类作为参数,并返回一个新的类。

函数装饰器示例:

def my_decorator(func):
    def wrapper():
        print("Start.")
        func()
        print("End.")
    return wrapper

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

say_hello()

类装饰器示例:

class MyDecorator:
    def __init__(self, func):
        self.func = func
    def __call__(self):
        print("Start.")
        self.func()
        print("End.")

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

say_hello()

代码说明:

类装饰器 MyDecorator 接受一个函数作为参数,并定义了 __call__ 方法,在该方法中添加了额外的操作,然后调用原函数。

在原函数 say_hello 上方添加了装饰器 @MyDecorator,实际上是将其传递给 MyDecorator 类,返回一个新的代理类。代理类的 __call__ 方法调用原函数并加上额外的操作。

最终,执行 say_hello() 时,实际上执行的是代理类的实例对象。输出结果同上。

三、装饰器的应用

装饰器可以用于函数的某些扩展功能,例如:添加日志、计时、缓存结果,以及权限控制等功能。下面将分别介绍这些应用场景的实现方法。

1、添加日志

在函数执行前后添加日志信息,可以帮助我们更好地了解函数的运行状况,便于分析问题和优化性能。下面是一个简单的添加日志的装饰器实现:

import logging

def log(func):
    def wrapper(*args, **kwargs):
        logging.basicConfig(filename=f"{func.__name__}.log", level=logging.INFO)
        logging.info(f"{func.__name__} started with args: {args}, kwargs: {kwargs}")
        result = func(*args, **kwargs)
        logging.info(f"{func.__name__} ended with result: {result}")
        return result
    return wrapper

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

print(add(2, 3))

代码说明:

定义了装饰器 log,它接受一个函数作为参数,并定义了新函数 wrapper,在该函数中添加了日志信息。

在原函数 add 上方添加装饰器 @log,实际上是将其传递给 log 函数,返回一个新函数作为原函数的代理对象。

最终,执行 add(2, 3) 时,实际上执行的是新函数 wrapper,输出结果为 5。同时,在当前目录下生成一个名为 add.log 的日志文件,其中包含了函数执行前后的日志信息。

2、添加计时器

在函数执行前后添加计时器,可以帮助我们了解函数的运行效率,便于优化性能。下面是一个简单的添加计时器的装饰器实现:

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.3f}s to run.")
        return result
    return wrapper

@timer
def add(a, b):
    time.sleep(1)
    return a + b

print(add(2, 3))

代码说明:

定义了装饰器 timer,它接受一个函数作为参数,并定义了新函数 wrapper,在该函数中添加了计时器。

在原函数 add 上方添加装饰器 @timer,实际上是将其传递给 timer 函数,返回一个新函数作为原函数的代理对象。

最终,执行 add(2, 3) 时,实际上执行的是新函数 wrapper,输出结果为 5。同时,输出计时器信息,如:add took 1.001s to run。

3、缓存结果

如果一个函数的计算结果是稳定的,那么可以使用缓存技术来避免重复计算,提高函数的执行速度。下面是一个简单的缓存结果的装饰器实现:

def cache(func):
    cached_results = {}
    def wrapper(*args):
        if args in cached_results:
            return cached_results[args]
        else:
            result = func(*args)
            cached_results[args] = result
            return result
    return wrapper

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

print(fibonacci(10))
print(fibonacci(20))

代码说明:

定义了装饰器 cache,它接受一个函数作为参数,并定义了新函数 wrapper,在该函数中添加了缓存技术。

在原函数 fibonacci 上方添加装饰器 @cache,实际上是将其传递给 cache 函数,返回一个新函数作为原函数的代理对象。

最终,执行 fibonacci(10) 和 fibonacci(20) 时,实际上执行的是新函数 wrapper,输出结果分别为 55 和 6765。同时,第二次执行 fibonacci(20) 时,实际上从缓存中返回了结果,不需要再次计算。

4、权限控制

在特定的场景下,需要对函数进行权限控制,例如:只有管理员才能删除数据。下面是一个简单的权限控制装饰器实现:

` python

def admin_required(func):

def wrapper(*args, **kwargs):

if kwargs.get("user") != "admin":

raise Exception("Permission denied.")

else:

return func(*args, **kwargs)

return wrapper

@admin_required

def delete_data(user, data_id):

print