关键词

详解 Python 函数装饰器的3种用法

Python 函数装饰器是一种特殊的函数,它有两个特点:

  1. 它可以接收一个函数作为参数,并返回一个新的函数作为此函数的替代。
  2. 它可以在不改变原有函数代码的情况下,增强原函数的功能或者修改原函数的行为。

装饰器本质上是一个闭包函数,它的目的是对原函数进行一层包装,以增强函数的功能或者修改函数的行为。

Python 装饰器语法

Python 装饰器的语法如下:

@decorator
def function_name(parameters):
    function_body

其中 @decorator 表示使用 decorator 来装饰 function_name 函数。当 function_name 被调用时,实际上执行的是 decorator(function_name) 函数。从这点我们可以发现,装饰器本质上就是一个函数,它接收一个函数作为参数,并返回一个新的函数。

下面通过一些示例来详细讲解 Python 函数装饰器的用法。

Python 装饰器增强函数的功能

下面是一个示例,演示了如何使用装饰器来增强函数的功能:


#装饰器函数
def log(func):
    def wrapper(*args, **kwargs):
        print("Calling function: {}".format(func.__name__))
        return func(*args, **kwargs)
    return wrapper

#要包装的函数
@log
def greet(name):
    print("Hello, {}!".format(name))

greet("Python技术站")

输出结果如下:

Calling function: greet
Hello, Python技术站!

在上面的示例中,log 装饰器接收一个函数作为参数,并返回一个新的函数 wrapper,wrapper 函数在调用原函数 func 之前,打印一行日志信息。通过在 greet 函数前加上 @log 装饰器,实现了对 greet 函数增加日志的功能。

Python 装饰器修改函数的行为

接下来这个示例,演示了如何使用装饰器来修改函数的行为:

#装饰器函数
def memoize(func):
    cache = {}
    def wrapper(*args):
        if args in cache:
            return cache[args]
        else:
            result = func(*args)
            cache[args] = result
            return result
    return wrapper

#要包装的函数
@memoize
def fibonacci(n):
    if n < 2:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))

输出结果如下:

55

在这个示例中,memoize 装饰器接收一个函数作为参数,并返回一个新的函数 wrapper。

wrapper 函数先检查缓存中是否已经存在计算结果,如果存在则直接返回缓存结果,否则调用原函数进行计算,并把结果存入缓存中。通过在 fibonacci 函数前加上 @memoize 装饰器,实现了对 fibonacci 函数的行为修改。

Python 函数装饰器的嵌套使用

在Python中,我们可以对函数进行嵌套使用,也就是一个函数可以有很多个函数装饰器。比如,我们可以定义一个函数装饰器来实现函数的缓存功能,然后再使用另一个函数装饰器来实现函数的日志记录功能。

下面是一个实现函数缓存和日志记录的例子:

#缓存装饰器
def memoize(fn):
    cache = {}
    def memoizer(*args):
        if args not in cache:
            cache[args] = fn(*args)
        return cache[args]
    return memoizer

#日志装饰器
def logger(fn):
    def wrapper(*args):
        print('calling {0} with args {1}'.format(fn.__name__, args))
        return fn(*args)
    return wrapper

#要包装的函数
@logger
@memoize
def fibonacci(n):
    if n in (0, 1):
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))

输出结果为:

calling memoizer with args (10,)
calling fibonacci with args (9,)
calling memoizer with args (8,)
calling memoizer with args (7,)
calling memoizer with args (6,)
calling memoizer with args (5,)
calling memoizer with args (4,)
calling memoizer with args (3,)
calling memoizer with args (2,)
calling memoizer with args (1,)
55

在这个例子中,我们定义了两个函数装饰器:memoize和logger。memoize用于缓存函数的结果,logger用于记录函数的调用信息。

我们可以看到,fibonacci函数同时被这两个函数装饰器装饰,因此它首先被memoize装饰器装饰,然后被logger装饰器装饰。当我们调用fibonacci(10)时,它会先被logger装饰器捕获,输出调用信息,然后被memoize装饰器捕获,检查缓存,如果缓存中有结果则直接返回,否则计算结果并将其保存到缓存中。

通过这个例子,我们可以看到函数装饰器的嵌套使用可以为函数提供多种不同的功能,并且这些功能可以按照任意顺序进行组合和叠加。这为我们编写复杂的函数提供了极大的便利。

本文链接:http://task.lmcjl.com/news/14609.html

展开阅读全文