软件开发中有⼀条⾮常重要的规则就是:对修改封闭,对扩展开放。对于⼀个现有的函数,如果想要增强此函数的功能,但是不允许修改此函数源代码的时候,使⽤装饰器来解决这个问题。
装饰器的本质就是一个闭包,是一个返回内部函数的高阶函数。它使我们在不修改原函数代码的情况下为原函数增加性的功能。
1.1.基本装饰器我们下面来举例说明装饰器的写法和用法。下面我们利用装饰器为hope()函数增加新的功能。
# 要增强的 hope() 函数,必须写在装饰器之前
def hope(name):
print(f"{name},加油!")
# 装饰器
def wrapper(func): # 装饰器的参数是要增强函数的函数名
def inner(name):
func(name) # 装饰器内部函数中要调用被增强的函数
print("等到春暖花开,我们一起看樱花满城!") # 要增加的功能
return inner # 返回内部函数的函数名
hope = wrapper(hope) # 将原 hope() 函数覆盖
hope("武汉")
执行结果如下,
武汉,加油!
等到春暖花开,我们一起看樱花满城!
1.2.@语法糖
@语法糖可以简化装饰器的调用过程,下面我们用@语法糖来调用hope()函数。
# 装饰器,与上面相同,没有变化
def wrapper(func):
def inner(name):
func(name)
print("等到春暖花开,我们一起看樱花满城!")
return inner
@wrapper # @ + 装饰器名称,等价于 hope = wrapper(hope),后面接要增强的函数
# hope()函数,与原来相同
def hope(name):
print(f"{name},加油!")
hope("武汉") # 直接调用hope()函数
执行结果如下,
武汉,加油!
等到春暖花开,我们一起看樱花满城!
我们看到执行结果相同,且较为简洁。
1.3.不定参数的装饰器我们将装饰器内部函数中的参数修改为任意位置参数和任意关键字参数,可以使得装饰器具有更强的适用性。
2.递归函数 2.1.嵌套调用和递归调用函数a调用函数b,函数b调用函数c,这就是嵌套调用。而递归调用是一种特殊的嵌套调用,在递归调用中,函数在不断的调用自己。
为了防止陷入死循环,我们需要为递归调用设置合理的终止条件。
2.2.递归的使用条件如果⼀个问题规模缩减后,求解⽅式和原来⼀样,⼩规模问题解决后导致问题的最终解决,则可适⽤递归。
例如,我们用递归函数的方法编写一个斐波那契数列的函数,
def fabo(n):
if n == 1 or n == 2: # 终止条件,fabo(1) = fabo(2) = 1
return 1
return fabo(n - 1) + fabo(n - 2) # 递归
print(fabo(9))
执行结果如下,
34