Python学习笔记:递归、闭包以及装饰器

发布时间 2023-07-24 19:19:11作者: 划船丢桨

一、首先,什么是递归?

首先,简单来说递归就是在运行的过程中不断调用自身,从而完成“递”“归”两个过程。

在Python当中递归函数也是这个道理,通过直接或者间接调用函数本身就叫递归函数。注:在Python中编写递归函数一定要有结束条件否则会导致内存溢出。

1、Python案例:

​ 首先通过一个例子了解递归的简单运用:

#递归函数
def outer(num):
    if num == 0 or num < 0: # 一定要记住要有结束条件,否侧栈溢出程序就会崩溃
        return True
    return num * outer(num-1) # 返回值调用函数本身

print(outer(6)) # 传入起始参数值,往后的值会依次递减。

​ 运行结果:

>> 720

2、结论:

​ 通过结果我们可以看出来最终的计算结果是720,上面的代码计算了从:6×5×4……一直乘以1的运算结果。首先函数outer()通过“num”参数将整数6传进去之后判断是否等于或者小于0符合条件则结束运算,不符合则执行执行后面的return关键字返回函数调用结果,一直到满足if条件则结束函数。注:其中有一个尾递归方法通过yield关键字返回参数可以避免调用太多次栈溢出,这次不做具体解释。

二、函数的闭包是什么?

在了解闭包函数之前首先需要了解嵌套函数,嵌套函数简单来说就是在一个函数里面再次编写一个函数。通过下面的例子让你简单了解一下函数的嵌套:

# 通常我们编写函数都是下面这样的
def foo():
    pass  #其中pass里面有函数方法执行体和返回值两种
#----------------------------------------------------------------------
# 而在Python函数当中可以像下面这样对函数进行嵌套处理
def func():
    print('hello world 1')
    def func2():
        print('hello world 2')

此时调用func函数会发生什么呢?

func()
>> 'hello world 1'

为什么只输出func函数的结果,func2的结果为什么没有输出呢?了解Python的都知道函数或者对象需要调用才能执行。那你一定想到那我就在下面调用func2函数不就行了?

>> NameError: name 'func2' is not defined

报错结果显示我们没有定义func2函数,通过这个我们就明白内部函数不能在外部函数之外调用,否则会报错。通过下面的调用方法就执行成功了。

def func():
    print('hello world 1')
    def func2():
        print('hello world 2')
    func2()
func()

# 输出结果:
>> 'hello world 1'
   'hello world 2'

1、Python案例:

​ 首先通过定义一个函数闭包实例,让你简单了解到闭包的运用。

# 函数的闭包
def outer(num):
    # 2.定义内部函数,在内部函数中使用外部函数的变量
    def inner(num1):
        print(num + num1)

    # 3.外部函数返回内部函数的地址
    def inners(num2):
        print(num + num2 + num)

    return innersi # 给定返回值,需要注意的是返回值函数地址是谁下面调用就执行谁,同样注意不用加上括号,加上括号就是直接执行函数本身变成嵌套函数
    # 需要注意的是,闭包函数有点类似于面向对象的方法,同样他也是Python装饰器的基础.

fun = outer(2) #fun相当于返回值的函数地址,将outer函数作为参数传给变量fun,在Python中函数可以传递给变量,有点类似于Class对象的实例方法
fun(1) #这个fun(1)相当于innersi(1),只不过前面有outer(2)进行赋值给fun。

2、结论:

简单来说学习函数闭包方法在后面学习装饰器当中扮演者重要角色,而在实际开发运用当中闭包可以将外部函数和内部函数连接起来,因为内部函数可以使用外部函数的参数值。这种函数式编程的思想可以使代码更加简洁、灵活、可复用,并且可以提高代码的可读性和可维护性。

三、对装饰器的使用。

​ 装饰器是一种特殊的函数,可以在不修改原函数代码的情况下,为其添加额外的功能。使用闭包可以实现装饰器的功能,例如:

# 装饰器将一个另外的函数作为参数传入
def my_shiny_new_decorator(a_function_to_decorate):
    # 定义一个wrapper
    def the_wrapper_around_the_original_function():
        # 在传入的函数被执行前执行
        print("Before the function runs")
        a_function_to_decorate() # 里面可以根据被装饰的函数进行传参,也可以赋值给变量在下面写上变量返回值,这里相当于执行了下面的a_stand_alone_function()函数。
        # 在传入的函数被执行后执行
        print("After the function runs")
    return the_wrapper_around_the_original_function

# @函数名相当于a_stand_alone_function=my_shiny_new_decorator(a_stand_alone_function)
@my_shiny_new_decorator  
def a_stand_alone_function():
    print("I am a stand alone function, don't you dare modify me")

a_stand_alone_function()
# 输出结果:  I am a stand alone function, don't you dare modify me
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
# 输出结果: 
# Before the function runs
# I am a stand alone function, don't you dare modify me
# After the function runs

3、总结:

通过上面的例子可以发现装饰器和闭包有点相似,没错装饰器就是一个闭包的运用。在实际开发当中,为了对代码进行额外功能的添加,Python装饰器诞生,他让代码省去了重复编写的麻烦同时简洁可复用。在需要装饰的函数上面通过@函数名就可以为函数增加额外功能,被装饰的函数相当于一个参数被传递进了装饰器里面,而带有参数的装饰器,可以在装饰器内部函数参数里面加上‘*args’, ‘**kwargs’(在不知道具体参数数量前提下),其中args是以元组进行传递,而kwargs是以字典进行值的传递。

四、补充知识点:

​ 在python当中函数可以作为变量传输进其他函数,通过调用一个函数执行多个函数的进阶运用。

# Python中万物皆是对象,函数也能进行变量传进其他函数,且能作为函数的返回值
def double(x):
    return x * 2
def triple(x):
    return x * 3
def calc_number(func, x):
    print(func(x))

calc_number(double, 3) #结果:6 double——表示指向哪一个函数的地址
calc_number(triple, 3) #结果:9 triple——表示指向哪一个函数的地址
print(double) #结果:<function double at 0x0000024CB1C67B80>|就会得到函数的地址,地址可以让程序明白函数是谁在哪里。
#--------------------------------------------------------
#或者像下面简单的运用
def double(x):
    return x * 2
def triple(x):
    return x * 3

def calc_number(x):
    print(double(x))
    print(triple(x))
    
calc_number(3)
"""
执行结果为:
6
9
"""