python闭包函数、装饰器、生成器

1. 闭包函数

什么是闭包函数

闭包函数就是在函数内部定义了一个函数(内嵌函数),并将这个函数的引用作为返回值返回。

但是闭包函数可以调用外部函数的形参和变量,并且在外部调用闭包函数时,其外部函数的形参和变量仍然生效

无参数的闭包函数

def out_func():
    print("外面的函数被调用") # 1

    def inner_func():
        print("里面的函数被调用 -- inner_func()") # 3

    print("外面的函数调用完成,返回inner_func的引用") # 2

    return inner_func


# out_func()的返回值是inner_func
x = out_func()
# x == inner_func
x()  
print(type(x))


# 执行结果
外面的函数被调用
外面的函数调用完成,返回inner_func的引用
里面的函数被调用 -- inner_func()

有参数的闭包函数

在调用外部函数时,闭包函数不会被执行,但是外部函数的变量和形参会被放入内存中,当外部调用闭包函数时,闭包函数仍然可以调用内存中其外部函数的形参和变量

def func_out(num1: int):
    a = 50
    def func_inner(num2: int):
        result = num1 + num2 + a
        print(f"外部函数的形参为{num1},内部函数的形参为{num2},外部函数的局部变量为{a},相加为{result}")

    return func_inner  # 注意不能加()



f = func_out(100) # 参数 100 是外部函数的传参num1
# 参数 200 是闭包函数的传参num2,因为此时f为func_inner
f(200)

# 运行结果

外部函数的形参为100,内部函数的形参为200,外部函数的局部变量为50,相加为350

2. 装饰器

什么是装饰器

装饰器本质就是一个闭包函数,它将装饰起来的函数当做参数传递到外部函数的形参,然后在其闭包函数中执行该函数。

装饰器的作用就是在被装饰函数的前后添加新的功能或限制。

无参数的装饰器

如果被装饰的函数带有参数,则需要在闭包函数中添加相应的形参,并在调用被装饰的函数时,将其传递进去

# 装饰器就是一个函数,它会返回一个函数的引用,并且形参有且只有一个
# 装饰器不会改变原函数的功能,它会在其外部(执行前或执行后)添加新的功能或限制
# 装饰器的本质就是一个闭包函数,只是把外部函数的传参是一个函数的引用,在内部函数调用了该函数

def check(func):
    def inner():
        print("开始登录")
        print("输入用户名和密码并登录")
        print("登录中...")
        print("登录成功")
        func()

    return inner


def check2(func):
    def inner(a):
        print("开始登录")
        print("输入用户名和密码并登录")
        print("登录中...")
        print("登录成功")
        func(a)

    return inner


# 1. 可以使用注解的方式添加装饰器
@check
def shopping():
    print("添加一件商品到购物车")


@check2
def shopping2(a):
    print(f"添加{a}件商品到购物车")


# 2. 将原有函数的引用指向装饰器的引用,并将原有函数的引用传递到形参中
# 如果不加装饰器,则需要下面这行代码才能运行shopping()
# shopping2(2)也是同理
# shopping = check(shopping) 
shopping()
shopping2(2)

有参数的装饰器

有参数的装饰器就是在无参数装饰器的基础上再套一层函数,用于将装饰器的参数传递进来,也就是三层函数。

因为第三层的函数需要装饰器的传参,但是第二层的函数的形参需要传递函数引用,所以在第三层函数传递装饰器的传参,然后返回第二层函数,这样第二次函数可以调用第三层函数的形参,也就是装饰器的传参,然后第二层装饰再返回最里面的闭包函数。

这样闭包函数既有装饰器的传参,也有被装饰的函数的引用

def mark(flag):
    def out_func(fn):
        def inner_func(num1, num2):
            print("开始计算...")
            print("计算完成,结果为:")
            print(fn(num1, num2))

        return inner_func

    return out_func


@mark('+')
def add(a, b):
    return a + b

@mark('-')
def sub(a, b):
    return a - b

# 如果不加装饰器则需要执行下面两行代码才能执行add(1, 2)
# sub(1, 2)也是同理
# out_func = mark()
# add = out_func(add)

add(1, 2)
sub(1, 2)

3. 生成器

什么是生成器

当一个函数是用来yield关键字时,它就是一个生成器

当生成器执行到yield时会跳出函数(可以返回数据),当下次再调用生成器时,会从上次调用的yield下面一行代码开始运行,直到遇到下一个yield,以此类推

当生成器的内容全部执行完毕之后,想要再次执行生成器需要重新赋值变量

生成器的使用

# 当函数中使用yield关键字时,该函数就是一个生成器
# yield的功能和return一样,可以结束函数的运行,并可以返回值

# yield和return的区别,当函数执行yield之后会退出函数,但是下次再调用该函数时会从上传调用yield的下面开始执行

def func1():
    print(1)
    print(2)
    print(3)
    print(4)
    print(5)
    yield 6
    print(7)
    print(8)
    print(9)
    yield 10
    print(11)
    print(12)
    print(13)
    yield


"""
   使用方法:
   1. 首先将函数赋值给一个变量fn
   2. 将变量fn传入到next()函数的形参 --> next(fn)
   3. 调用next(fn)就相当于调用生成器
   4. 当生成器内容完全执行完后,该变量不会重新开始生成器的内容
"""

fn = func1()
print("第一次调用生成器")
print(f"生成器返回值:{next(fn)}")
print("第二次调用生成器")
print(f"生成器返回值:{next(fn)}")
print("第三次调用生成器")
print(f"生成器返回值:{next(fn)}")

print('-' * 100)

# 再次调用需要重新赋值
fn1 = func1()
print("第一次调用生成器")
print(f"生成器返回值:{next(fn1)}")
print("第二次调用生成器")
print(f"生成器返回值:{next(fn1)}")
print("第三次调用生成器")
print(f"生成器返回值:{next(fn1)}")
def func2():
    i = 0
    while i < 10000:
        if i == 3000:
            yield i
        i += 1

    yield i


fn2 = func2()
print(next(fn2))
print(next(fn2))

yield和return的区别

相同点:yield的功能和return一样,可以结束函数的运行,并且可以返回值。

区别:yield调用后退出函数,下次调用函数时,会从yield下面开始执行函数,return退出后会从头开始执行函数。

你可能感兴趣的:(python,开发语言)