一、递归
    函数和方法的调用很多时候发生在不同的函数和方法之间,比如定义了def func_a函数与def func_b函数,在func_b函数中调用func_a,当然还存在一个特殊调用,即函数内部调用自身,这种调用方式就叫作递归调用,好处是大大减少代码量,把复杂问题简单化
    计算一个阶乘如10!(s = 12345….*10)
    递推方式实现

    1. def iterative(n):
    2. num = 1
    3. for i in range(1,n+1):
    4. #num *= i
    5. num = num * i
    6. return num

    以1为基数通过for循环来实现阶乘计算,注意一个这个range(1,n+1 )前包含后不包含,所以取n+1

    递归方法实现

    1. def recursive(n):
    2. if n <=1 :
    3. return n
    4. else:
    5. return n * recursive(n-1)

    yuque_diagram.jpg
    递归缺点:运行速度慢于递推,内存消耗比较大

    1. # 1,1,2,3,5,8,13,21,34,55,试判断数列第十五个数是哪个?
    2. def fabonacci(n):
    3. ''' n为斐波那契数列 '''
    4. if n <= 2:
    5. ''' 数列前两个数都是1 '''
    6. v = 1
    7. return v # 返回结果,并结束函数
    8. v = fabonacci(n-1)+fabonacci(n-2) # 由数据的规律可知,第三个数的结果都是前两个数之和,所以进行递归叠加
    9. return v # 返回结果,并结束函数
    10. print(fabonacci(15)) # 610 调用函数并打印结果

    yuque_diagram (1).jpg
    非递归写法

    1. # 斐波那契数列
    2. def fib(n):
    3. a, b = 1, 1
    4. for i in range(n-1):
    5. a, b = b, a+b
    6. return a
    1. n=5fib(5)
    2. print("a","b")
    3. for i in range(5-1):
    4. a, b = b, a+b
    5. print(a, b)
    6. 结果:
    7. a b
    8. 1 2
    9. 2 3
    10. 3 5
    11. 5 8

    二、装饰器
    前提概念一:
    闭包:在函数中再嵌套一个函数,并且引用外部函数的变量,这就是一个闭包了

    1. def outer(x):
    2. def inner(y):
    3. return x + y
    4. return inner
    5. print(outer(6)(5))

    函数中可定义函数

    1. def func_1():
    2. print("正在调用func_1")
    3. def func_1_1():
    4. return "正在调用func_1_1"
    5. def func_1_2():
    6. return "正在调用func_1_2"
    7. print(func_1_1())
    8. print(func_1_2())
    9. print("函数func_1调用结束")
    10. #
    11. 正在调用func_1
    12. 正在调用func_1_1
    13. 正在调用func_1_2
    14. 函数func_1调用结束

    函数中定义的函数,只能在func_1函数内调用
    前提概念二:
    函数中返回函数

    1. def func_1():
    2. print("正在调用func_1")
    3. def func_1_1():
    4. return "正在调用func_1_1"
    5. print("函数func_1调用结束")
    6. return func_1_1
    7. a = func_1() #正在调用func_1
    8. 函数func_1调用结束
    9. print(a) # <function func_1.<locals>.func_1_1 at 0x000001B92BE3DAF0>
    10. print(a()) # 正在调用func_1_1

    问题:为什么 print(a) 与 print(a( ))不一样?
    前提概念三:
    赋值与调用

    1. def func_2():
    2. print("函数func_2被调用")
    3. a = func_2
    4. print(a) # <function func_2 at 0x00000219AAD8F040>
    5. b = func_2() # 函数func_2被调用
    6. c = a() # 函数func_2被调用

    从上述代码可知,当 a = func_2 时,是把func_2函数对象内存地址赋值给变量a,并不会执行func_2这个函数中的代码;当 b = func_2( )时,函数func_2( )会被调用,加上()会运行这个函数中的代码
    装饰器:
    在Python中,可以把函数A作为参数传入另一个函数B,从而实现在不改变函数A原有代码的基础上对函数A增加新功能

    1. def func_A():
    2. print("A函数本身的功能")
    3. def func_B(func):
    4. print("执行func_B开始")
    5. def func_b():
    6. print("func_b执行传入函数前做一些事情")
    7. func()
    8. print("func_b执行传入函数后做一些事情")
    9. print("准备返回func_b")
    10. return func_b
    11. b = func_B(func_A) # func_B()执行返回一个 func_b 内嵌函数对象给func_A调用
    12. '''
    13. 执行func_B开始
    14. 准备返回func_b
    15. func_b执行传入函数前做一些事情
    16. A函数本身的功能
    17. func_b执行传入函数后做一些事情
    18. '''

    上述代码func_B函数就是一个装饰器函数,但需要调用func_B函数来实现对func_A函数的功能拓展,
    通过@符号装饰func_A函数,可实现直接调用func_A函数来达成装饰器的目的

    1. @func_B
    2. def func_A():
    3. print("A函数本身的功能")
    4. func_A()
    5. '''
    6. 执行结果:
    7. 执行func_B开始
    8. 准备返回func_b
    9. func_b执行传入函数前做一些事情
    10. A函数本身的功能
    11. func_b执行传入函数后做一些事情
    12. '''

    被装饰的A函数有单个参数

    1. def func_B(func):
    2. def func_b(x):
    3. return 2*func(x)
    4. return func_b
    5. @func_B
    6. def func_A(x):
    7. return int(x)+1
    8. if __name__ == "__main__":
    9. a = func_A(2)
    10. print(a)
    11. print(func_A.__name__) # 结果为func_b,即func_A被装饰后指向了func_b

    被装饰的A函数有多个参数

    1. def func_B(func):
    2. def func_b(*args,**kwargs):
    3. return 2*func(*args,**kwargs)
    4. return func_b
    5. @func_B
    6. def func_A(x,y):
    7. return int(x)+int(y)
    8. if __name__ == "__main__":
    9. a = func_A(2,3)
    10. print(a)