十三. Python基础(13)--生成器进阶

时间:2023-03-06 18:20:44

十三. Python基础(13)--生成器进阶

1 ● send()方法

generator.send(value)

Resumes the execution, and "sends" a argument which becomes the result of the current yield expression in the generator function.

 

The send() method, like __next__(), returns the next value yielded by the generator, or raises StopIteration if the generator exits without yielding another value.

When send() is called to start the generator, it must be called with None as the argument, because there is no yield expression that could receive the value.

 

2 ● send()函数的简单案例

def fun():

    print('*')

    value = yield 1

    print('**', value)

    yield 2

 

g = fun()

print(g.__next__())

# print(g.__next__()) # ** None

print(g.send("aaa")) # ** aaa

# print(g.send("bbb")) # 警示"StopIteration"异常, 因为此时"bbb"没有可以用来赋值的的yield表达式

'''

*

1

** aaa

2

'''

# send()和__next__()工作的起始位置是完全相同的

# send()可以把一个值作为信号量(semaphore)传到函数中去

# 在生成器执行伊始, 只能先用__next__()或send(None), 因为用send()传递非None参数的时候,在生成器中必须有一个未被赋值的yield表达式

# __next_()方法以及send()方法的数量 不同多于 yield表达式的数量, 否则警示异常StopIteration.

 

3 ● 计算累计平均数

def wrapper(func): # 这个装饰器中只做一件事:g.__next__; 或者next(g), 也就是激活生成器(next是内置函数)

    def inner(*args, **kwargs):

        g = func(*args, **kwargs) # 最好不要跟外面的创建的gen生成器重名

        g.__next__() # 也可以是g.send(None), 用来激活生成器

        return g

    return inner

 

@wrapper

def average_func():

    total = 0

    count = 0

    average = 0

    while True: # 这个while True可以让使用者一直使用send方法, 也就是调用这个函数的可生成一个取之不尽用之不竭的生成器, 注意这里不会造成死循环

        value = yield average

        total += value

        count += 1

        average = total/count

 

gen = average_func()

print(gen.send(30))

print(gen.send(50))

print(gen.send(10))

'''

30.0

40.0

30.0

'''

 

4 ● 列表推导式/字典推导式/集合推导式(没有元组推导式)

列表推导式:

for i in range(0, 21, 2)
if ]) # [0, 4, 16, 36, 64, 100]

字典推导式:

案例①:

dic = {'k1':'v1', 'k2':'v2'}

print({dic[key]: key
for key in dic})

# {'v1': 'k1', 'v2': 'k2'}

 

案例②:

dic = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}

dic_new = {k.lower(): dic.get(k.lower(), 0) + dic.get(k.upper(), 0)
for k in dic.keys()}

print(dic_new)

# {'a': 17, 'b': 34, 'z': 3}

集合推导式: (自带去重的功能)

print({i**2 for i in [1, -1, 2]})

# {1, 4}

 

5 ● 生成器表达式

把列表解析的[]换成()得到的就是生成器表达式.

gen_list = (i**2 for i in range(0, 21, 2) if i < 11)

for i in gen_list:

    print(i)

'''

0

4

16

36

64

100

'''

dic = {'k1':'v1', 'k2':'v2'}

gen_a = (key for key in dic)

gen_b = (key for key in dic.items())

for i in gen_a:

    print(i)

for i in gen_b:

    print(i)

'''

k1

k2

('k1', 'v1')

('k2', 'v2')

'''

gen_col = (i**2 for i in {1, -1, 2})

for i in gen_col:

    print(i)

'''

1

4

1

'''

 

6 ● 面试题1

def demo():

    for i in range(4):

        yield i

 

g=demo()

 

g1=(i for i in g)

g2=(i for i in g1)

 

print(list(g1)) # [0, 1, 2, 3]

print(list(g2)) # []

 

7 ● 面试题2

def add(n,i):

    return n+i

 

def test():

    for i in range(4):

        yield i

 

g=test()

for n in [1,10]:

    g=(add(n,i) for i in g) # 生成器推导式

    print(list(g))

 

# [1, 2, 3, 4]

# []注意这一步是没有数跟10相加, 因此为空.

def add(n,i):

    return n+i

 

def test():

    for i in range(4):

        yield i

 

g=test()

for n in [1,10]:

    g=(add(n,i) for i in g)

 

print(list(g))

 

'''

① 上面的三个g是三个不同的迭代器

② 上面一段相当于:

n = 1

g=(add(1,i) for i in range(4)) # 1+0+1+2+3=7 # 生成器中的数据没有被获取, 因为生成器只有在被调用的时候才会生成相应的数据(用__next__()、 for、list调用, 或被其它函数调用), 反之就不会生成--惰性运算.

n = 10

g=(add(n,i) for i in g)

print(list(g))

'''

 

# [20, 21, 22, 23]

如果这里是:

n=1

g=(add(n,i) for i in g) # 生成器推导式

n=10

g=(add(n,i) for i in g)

n=5

g=(add(n,i) for i in g)

print(list(g))

 

那么相当于运行:

for n in [1,10,5]:

g=(add(n,i) for i in g) # 生成器推导式

print(list(g))

 

即:

n=1

g = (add(n,i) for i in g)

n=10

g = (add(n,i) for i in (add(n,i) for i in g))

n=5

g = (add(5,i) for i in add(n,i) for i in (add(n,i) for i in g))

 

# [15, 16, 17, 18]