一闭三器

所谓一闭三器,是指闭包、装饰器、迭代器、生成器。

一、闭包

内部函数引用外部函数的变量(非全局变量),外部函数返回内部函数(返回内部函数的函数名),内部函数就是闭包函数。

所以闭包有以下特点:

  • 函数嵌套
  • 内部函数使用外部函数的变量
  • 外部函数返回内部函数名

示例1:

def outer(m):
    def inner(n):
        return print(m + n)
    return inner

func1 = outer(10)  # func1相当于inner,m=10
func1(20)          # 相当于inner(20), m=10,n=20

示例2:

def outer():
    m = 10
    print(m)
    def inner(n):
        m = 20    # 相当于在内层函数中新定义了一个变量,和外层函数的m无关,不会影响到外层函数的m              
        return print(f'内层m:{m}  n:{n} ')
    inner(3)
    print(f'外层m:{m}')
    return inner

func1 = outer()
# 10
# 内层m:20  n:3 
# 外层m:10

内层函数中对和外层函数同名的变量进行赋值时,是在内层新声明了一个和外层函数变量同名的变量,不会对外层函数的变量产生影响,类似局部变量和全局变量的关系。

二、装饰器 Decorator

装饰器的本质是一个闭包。装饰器可以在不改变函数功能的基础上,给函数增加一些功能。装饰器可以让代码更简洁。

示例1:

def external(func):
    def inner():
        print('start')
        func()
        print('end')
    return inner

@external
def sport():
    print('sport')

@external
def game():
    print('game')
    return 'happy'

sport()
g = game()
print(g)    # None

由于装饰器external的内部函数inner没有返回值,被装饰的game函数也无法获取返回值。因此可以改进如下:

示例2:

def external(func):
    def inner():
        print('start')
        res = func()
        print('end')
        return res
    return inner

@external
def sport():
    print('sport')

@external
def game():
    print('game')
    return 'happy'

sport()
# start
# sport
# end
g = game()
# start
# game
# end
print(g)    # happy

如果sport和game函数有参数,且参数个数不同,要能同时对sport和game函数进行装饰,可以改进如下:

示例3:

def external(func):
    def inner(*args, **kwargs):     # 可以接收任意参数
        print('start')
        res = func(*args, **kwargs)
        print('end')
        return res
    return inner

@external
def sport(name, addr):
    print(f'{name} do sport {addr}')

@external
def game(hours):
    print(f'game {hours} hours')
    return 'happy'

sport('tom', 'outside')
# start
# tom do sport outside
# end
g = game(3)
# start
# game 3 hours
# end

 三、迭代器 iterator

迭代器(iterator)与可迭代对象(iterable

  • 可以用for循环遍历的对象,都是可迭代对象。可迭代对象包含 iter() 方法。(__iter__())
  • 迭代器是可迭代的对象,它包含方法 iter() 和 next() 方法。(或者说__iter__()、__next__())

列表、元组、字典和集合都是可迭代的对象。它们是可迭代的容器,可以从中获取迭代器(Iterator)。

str = '大家好'
str2 = str.__iter__() # 或 str2 = iter(str)
print(str2)     # <str_iterator object at 0x000001D8869CAC20>
print(str2.__next__())  #
print(next(str2))       #
print(next(str2))       #

迭代器从第一个元素开始访问,直到访问所有元素时结束。

while循环遍历迭代器:

iter1 = '大家好'.__iter__()
while True:
    try:
        print(next(iter1))
    except StopIteration:
        break

四、生成器 generator

生成器的本质就是迭代器。在每次迭代时返回一个值,直到抛出 StopIteration 异常。

创建生成器的方式:

(1)生成器函数

使用关键字 yield,函数中出现了 yield,那该函数就是一个生成器函数;生成器函数执行的时候,并不会立即执行函数,得到的是生成器。

  • 生成器可以通过 yield 返回数据

  • 可以分段执行函数的内容,通过 next,执行到下一个 yield 的位置

def func1():
    print('hello')
    yield '你好'

f = func1()
print(f)    # <generator object func1 at 0x0000029349D7C6D0>
ret = f.__next__()  # hello
print(ret)          # 你好
def func2():
    print('第一部分')
    yield 'aaa'
    print('第二部分')
    yield 'bbb'

f = func2()
res1 = next(f)      # 第一部分
print(res1)         # aaa
res2 = next(f)      # 第二部分
print(res2)         # bbb

和 return 相比,yield 除了可以返回相应的值,还有一个更重要的功能,即每当程序执行完该语句时,程序就会暂停执行。

不仅如此,即便调用生成器函数,Python 解释器也不会执行函数中的代码,它只会返回一个生成器(对象)

def func3():
    list1 = []
    for i in range(1, 11):
        list1.append(f'No {i}')
    yield list1     # 前面for循环执行完毕才到该行 yield,因此list1有10个元素

f = func3()
print(f)                # <generator object func3 at 0x000002B7C060DD20>
print(f.__next__())     # ['No 1', 'No 2', 'No 3', 'No 4', 'No 5', 'No 6', 'No 7', 'No 8', 'No 9', 'No 10']

 (2)生成器表达式

(表达式 for 变量 in 序列 if 条件) 

列表生成式中提过,使用小括号的生成式并不是返回一个元组,而是返回一个生成器对象。

g = (x for x in range(1, 11) if x % 2 == 0)
print(g)            # <generator object <genexpr> at 0x0000023A9728DD20>
print(next(g))      # 2
print(next(g))      # 4
print(next(g))      # 6

 

posted on 2023-04-08 13:39  木去  阅读(153)  评论(0)    收藏  举报