【Python学习之十】yield之send方法

yield作用

  简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator。下面以斐波拉契数列来做个说明:

# 普通的函数实现
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return ‘done‘
"""不足:
在 fab 函数中用 print 打印数字会导致该函数可复用性较差
因为其他函数无法获得该函数生成的数列。
""" 

# 返回一个 List
def fib(max):
    n, a, b = 0, 0, 1
    L = []
    while n < max:
        L.append(b)
        a, b = b, a + b
        n = n + 1
    return L
"""不足
该函数在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,最好不要用 List
来保存中间结果,而是通过iterable对象来迭代。
""" 

# 使用yield
def fab(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        # print b
        a, b = b, a + b
        n = n + 1
"""
带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行fab函数,而是返回一个 iterable对象
"""

下面执行yield版的fab函数:

# 运行
for n in fab(5):
    print(n)

# 结果
1
1
2
3
5

  在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

yield send方法

  关于生成器中的send方法,之前没理解,只知道有一个next方法。通过下面代码实例,记录一下自己的理解:

def func1():  # 生成器函数
    x = yield 1
    print(‘This is x in func1: ‘, x)
    x = yield x
    # print(‘This is x:‘, x)

f1 = func1()
print(‘This is next(f1): ‘, next(f1))
# 当调用next(f1)方法时,python首先会执行func1方法的yield 1语句
# next方法返回值为yield关键字后面表达式的值,即为1
# 此时方法func1中断执行,x的赋值以及之后的语句,不再执行

# 执行send方法或next方法:
print("This is f1.send(‘e‘):", f1.send(‘e‘))
# print("Second next:", next(f1))

# 当调用f1.send(‘e‘)方法时,恢复之前yield引起的中断
# 继续执行 x = yield 1,对x赋值
# 此时(yield 1)的返回值是send方法的参数值‘e‘,并将其赋值给x
# 然后继续执行 print(‘This is x in func1: ‘, x)
# 执行结果是This is x in func1: e

# 当调用next方法—>print("Second next:", next(f1))
# func1会从之前的中断—>yield 1语句,继续运行
# 语句 print(‘This is x in func1: ‘, x) 将被执行。
# 但是,此时yield 1的返回值是None,并将其赋值给x
# 因此,执行结果是:This is x in func1: None

# 如果调用f1.send(‘e‘)方法,则接下来继续执行,会遇到yield x语句
# func1再次被挂起。
# 此时,send方法的返回值为yield关键字后面表达式的值,即是x的值‘e‘
# 执行结果是:This is f1.send(‘e‘): e
# 如果func1方法内无 yield x 语句,将会报错:StopIteration

# 如果此时再次调用send方法
# print("This is f1.send(‘f‘):", f1.send(‘f‘))

# 此时表达式(yield x)的返回值定义为send方法参数的值,即为‘f‘
# 接下来x = yield x 这一赋值语句会将x的值置为‘f‘
# 继续运行,func1方法执行完毕,抛出StopIteration异常
# f1.send(‘f‘)也就没有返回值了。
# 但是,我们可以在func1方法,x = yield x语句后,中加入一条语句
# print(‘This is last x: ‘, x),用来测试x的值‘f’

总之,send方法和next方法的区别在于,执行send方法时,会首先把send方法内的参数赋值给上一次挂起的yield语句的返回值。但是需要注意,在一个生成器对象没有执行next方法之前,由于没有yield语句被挂起,所以执行send方法会报错:

TypeError: can‘t send non-None value to a just-started generator

但是,下面的语句是可行的:

f2 = func1()
print("Send None value: ", f3.send(None))
# 运行结果# Send None value:  1

当send方法的参数为None时,它与next方法完全等价。但是注意,虽然上面的代码可以接受,但是不规范。所以,在调用send方法之前,还是先调用一次next方法为好。

  以上,就是我通过查找资料,搞清楚yield 中send方法的过程与心得。感谢:https://blog.csdn.net/hedan2013/article/details/56293173  提供的参考。

原文地址:https://www.cnblogs.com/cjvae/p/9365899.html

时间: 2024-08-01 05:02:54

【Python学习之十】yield之send方法的相关文章

PYTHON学习0038:函数---生成器send方法---2019-7-2

函数生成器中,send的作用:1.换新生成器继续执行2.发送一个信息到生成器内部.和next()的区别:next只是唤醒生成器并继续执行,next()就相当于没有发送值或者默认发送一个None给函数内部.send(None)和next()效果一样.例子:def range(n):count=0while count<n:print("count",count)count+=1sign=yield countprint("------sign",sign)t=r

python学习[第十二篇] 数据类型之 集合

python学习[第十二篇] 数据类型之 集合 集合概念 python中集合是一组无序排列的哈希值.集合分为两种可变集合(set)和不可变集合(frozenset) 对可变集合可以修改和删除元素,对于不可变集合不允许.可变集合是不可以哈希的,因此既不能用作字典的键,也不能做其他集合的元素. 集合的增删改查 集合的创建于赋值 集合与列表([]) 和字典({})不同,集合没有特别的语法格式.列表和字典可以通过他们自己的工厂方法创建,这也是集合的唯一的创建方式.set()和frozenset() #创

python学习之生成器yield

python学习之生成器yield **yield的作用是使函数生成一个结果序列而不是一个值,任何使用yield的函数都称为生成器,调用生成器会创建一个对象,该对象通过连续调用next()或者__next__()方法生成结果序列** 一般情况 >>> def count(n,m): >>> print('这是一个循环外部测试') >>> while n>0: >>> print('这是一个循环内部测试') >>>

python学习笔记十——异常处理

1.try: command except 错误类型,记录错误信息变量: command finally: command try...finally的用处是无论是否发生异常都要确保资源释放代码的执行.一般来说,如果没有发生错误,执行过try语句块之后执行finally语句块,完成整个流程.如果try语句块发生了异常,抛出了这个异常,此时就马上进入finally语句块进行资源释放处理.如下从几个细节讨论finally的特性. 1).try中的return: 当在try语句块中含有return语句

python学习第十课续 :线程池

线程分步走 t=threading.Thread(target=fun,args=()) t.start() 执行流程:         threading.Thread(target=fun,args=()) à           self.__target = target          self.__name = str(name or _newname())          self.__args = args         t.start  à           _star

python学习第十节(yield表达式的应用+内置函数)

上节复习 yield表达式g.send(1)send函数是相当于next并且给yield传一个值,先传值,再next 加上装饰器 yield表达式的应用 第一个是当前目录的地址第二个是当前目录下的目录第三个是当前目录下的文件再次next(g)就可以查看当前目录下第一个目录下的信息 ##############下面是更改版本##################### 内置函数all() 所有为true才为trueany() 只要有true 就为truebin()十进制转为2进制oct()十进制转为

python 学习三十五天(socket的更多方法)

1.黏包 2.socket的更多方法介绍 3.验证客户端连接合法性 4.socketserver模块 一.黏包 1.现象: res=subprocess.Popen(cmd.decode('utf-8'), shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) 的结果的编码是以当前所在的系统为准的,如果是windows,那么res.stdout.read()读出的就是GBK编码的,在接收端需要用GBK解码 且只能从管道里读一次结果

python学习笔记-Day8 下 (特殊方法、iter方法、super方法、有序字典实现、python单例模式)

使用特殊方法实现字典 # 使用像字典 dic['xx'] 带中括号的类使用 # 简要介绍 class Foo: # ① 对象[xx] 调用的方法 def __getitem__(self, item): return 'getitem' # ② 对象[xx] = xxx 调用的方法 def __setitem__(self, key, value): return 'setitem' # ③ del 对象[xx] 调用的方法 def __delitem__(self, key): return

Python学习之路 - yield生成器,迭代器

生成器 把结果保存成生成器的状态,普通的函数中出现yield,就变成生成器. 1.Python 3.3 中 xrange已合并到range. 1 i = range(10) 2 print (i) 3 4 =>range(0, 10) 2. yield 生成器. 1 def func(): 2 print(111) 3 yield 1 4 print(222) 5 yield 2 6 print(333) 7 yield 3 8 return "done" 9 10 k = fu