yield表达式形式

首先了解

1.iterator

iterator叫做迭代器,用来遍历可以序列化的数据,比如一个list,set 等,当然如果对象想要能够使用迭代器来遍历,只要在该对象的类中添加__iter__()方法,该方法返回一个迭代器对象,迭代器对象中需要实现next()方法

for example:

>>> class sequenceClass(object):  
...     def __init__(self, *args):  
...             self._data = list(args)  
...     def __iter__(self):  
...             return DataIter(self)  
...  
  
>>> class DataIter(object):  
...     def __init__(self, data):  
...             self._index = 0  
...             self._data = data._data  
...     def next(self):  
...             if self._index >= len(self._data): raise StopIteration()  
...             d = self._data[self._index]  
...             self._index += 1  
...             return d  
...   
>>> data = sequenceClass(1,2,3,4)  
>>> for x in data: print x  
...   
1  
2  
3  
4

执行方法如下:
    创建对象data :   data = sequenceClass(1,2,3,4)
    使用for循环遍历data:

1.第一次for循环遍历data时,调用了data的__iter__()方法,该方法返回一个迭代器对象:DataIter

2.接着for循环每次调用DataIter对象的next()方法,next()方法返回数据

3.等到数据遍历完成时,抛出异常StopIteration, 该异常被for循环扑获,遍历结束。

以上是iterator的实现方法,但有一种更加简单的方式,但初学时可能不太好理解,就是使用yield表达式来遍历对象。

2.yield表达式及genetator

Python中,凡是含有yield的函数,被调用时都返回一个generator对象。generator设计的目的是能够更加简单的实现迭代器协议,例如上面的例子,需要单独写一个类来遍历数据,而用generator,直接一个yield表达式就可以用做迭代器了

>>> def test_generator():  
...     s = 0  
...     for i in xrange(10):  
...             s = yield i * s  
...             print ‘i:‘, i  
...             print ‘s:‘, s  
...             print ‘i * s‘, i * s  
...   
>>> t = test_generator()  
>>> t  
<generator object test_generator at 0x10403a820>  
>>>   
>>> t.next()  
0  
>>> t.send(10)  
i: 0  
s: 10  
i * s 0  
10  
>>> t.send(11)  
i: 1  
s: 11  
i * s 11  
22

执行方法如下:

1.定义了一个函数叫做test_generator

2.调用test_generator,得到t对象

3.运行t时,是一个generator对象

4.t.next()或者t.send(None)启动generator对象, generator对象运行到yield,将yield右面的表达式的值返回,并保存generator对象当前的状,因此,后面的打印都没有被执行。

5.t.send(10)

1)将输入的值10赋值给s

2)执行yield后面的表达式,即将所有print执行完毕,解析如下:

由于在第4步generator保存了对象的当前的状态,因此: i = 0, s是刚输入的值为10, i *s 当然就为0了,接着进入下一次循环,此时i= 1,执行yield表达式,结果得10,保存当前generator状态,返回10,generator停止运行。

6.t.send(11)

1)和第5步类似了,将11输入给s

2)因为第5步,generator保存了当前的对象的值,因此: i = 1, s是刚输入的值为11, i *s 当然就为11了,接着进入下一次循环,此时i= 2,执行yield表达式,结果得22,保存当前generator状态,返回22,generator停止运行。

7.接下来在调用t.send(num),和第5,6步一样,直到generator内部的循环完成,当再次调用时,将抛出异常:StopIteration

总结一下:

1. yield表达式, 四种形式:

a. 不接受输入值或者输入值是None

yield 1

b. 接受输入值

s = yield 1

c. 接受输入,但不返回数据,这样默认返回None

s = yield

d.既不接受输入,也不返回值,默认返回None

yield

第一种:当函数调用到yield时,返回yield的右边经过计算的值 ,这里说计算的意思是,yield后面可以写成函数,表达式等,

第二种:当函数调用到yield时,必须传入一个值,该值存入s中,然后返回yield后面的表达式的值并保存当前状态

第三种:只是将数据接受进来,然后执行yield后的语句,再次执行到yield时,保存当前状态并返回,这样的用例一般是

只打印一些处理消息,而不需要结果的方式。

第四种:这样的只能遍历generator内部的数据了。

2.使用generator的好处:

1)可以很方便的实现迭代器,即yield不接受输入值

2)使用generator可以减少内存的使用,因为遍历出来的值都是每次进行计算的,不用一次性全部计算完成,然后一个个

遍历,最终释放掉;另外可以在yield后面做一些操作,可以很随意的控制返回值。

3.coroutine 协程

使用yield的函数,若用send来控制,就算coroutine了,若用for循环来控制,就算generator或者iterator,使用方法大多见于

decorator, 如tornado中的gen.coroutine。

实例:

#应用:grep -rl ‘root‘ /etc    模拟linux中的grep -rl 命令,来过滤含有root内容的文件,并打印文件名
# import os
# def f1(func):              #程序初始化
#     def wrapper(*args, **kwargs):
#         g=func(*args, **kwargs)
#         next(g)
#         return g
#     return wrapper
# #阶段一,递归的找文件的绝对路径,把路径发给阶段2
# @f1
# def search(target):
#     ‘search file abspath‘
#     while True:
#         start_path = yield
#         g = os.walk(start_path)
#         for par_dir, _, files in g:
#             for file in files:
#                 file_path = r‘%s\%s‘ % (par_dir, file)
#                 target.send(file_path)
# #阶段2,收到文件路径, 打开文件获取对象,吧文件对象发给阶段3
# @f1
# def opener(target):
#     ‘get file obj: f = open(file_path)‘
#     while True:
#         file_path = yield
#         with open(file_path, ‘r‘, encoding=‘utf-8‘) as f:
#             target.send((file_path, f))
# #阶段三,收到文件对象,for循环读取文件的每一行内容,把每一行内容发给阶段4
# @f1
# def cat(target):
#     ‘read file‘
#     while True:
#         file_path,f = yield
#         for line in f:
#             res = target.send((file_path, line))
#             if res:
#                 break
# #阶段4,收到一行内容,判断root是否在这一行,如果在,则把文件名发给阶段五
# @f1
# def grep(target, pattern):
#     ‘grep functhion‘
#     tag=False
#     while True:
#         file_path, line = yield tag
#         tag = False
#         if pattern in line:
#             target.send(file_path)
#             tag=True
# #阶段五,收到文件名,打印结果
# @f1
# def printer():
#     ‘print function‘
#     while True:
#         filename = yield
#         print(filename)
# start_path1 = r‘E:\Pycharmlx\June\day\day21root‘
# start_path2 = r‘E:\Pycharmlx\June\day\day21root\t‘      #绝对路径
# g = search(opener(cat(grep(printer(), ‘root‘))))
# # print(g)
# g.send(start_path1)
# g.send(start_path2)
时间: 2024-08-12 03:49:07

yield表达式形式的相关文章

22、yield表达式形式和面向过程编程

一 yield的表达式 def foo(): print('starting') while True: x=yield None#return 2 print('value :',x) g=foo() print(next(g)) print(g.send(2)) 运行结果: starting #运行函数,打印starting后碰到yield停住 None #next()触发后 yield将None赋值给x,打印None后循环碰到yield停住 value : 2 #g.send(2)将2赋值

yield的表达式形式与内置函数

yield的功能: 1. 与return类似,都可以返回值,不一样在于,yield可以返回多个值而且可暂停,再次执行可继续下一步操作,return到了就停止不在继续运行. 2.为封装好的的函数能够使用__iter__和__next__方法, 3.遵循迭代器的取值方式 .__next__(),触发函数的执行和函数的保存都是通过yeild保存的.  . 一:yield的表达式形式 def foo(): print('starting') while True: x=yield #yield的表达式形

yield的表达式形式、面向过程编程(grep -rl &#39;root&#39; /etc)

一.yield的表达形式 def foo(): print('starting') while True: x=yield None#return 2 print('value :',x) g=foo() print(next(g)) print(g.send(2)) 运行结果: starting #运行函数,打印starting后碰到yield停住 None #next()触发后 yield将None赋值给x,打印None后循环碰到yield停住 value : 2 #g.send(2)将2赋

Day9:yield的表达式形式、面向过程编程(grep -rl &#39;root&#39; /etc)

一.yield的表达式 def foo(): print('starting') while True: x=yield None#return 2 print('value :',x) g=foo() print(next(g)) print(g.send(2)) 运行结果: starting #运行函数,打印starting后碰到yield停住 None #next()触发后 yield将None赋值给x,打印None后循环碰到yield停住 value : 2 #g.send(2)将2赋值

python函数(五)—yield的表达式形式

函数体内含有yield关键字,那该函数的执行结果是生成器对象 生成器对象的本质就是迭代器,所以yield的功能是 1.把函数的执行结果做成迭代器 2.可以返回多次值,而return只能返回一次值 3.可以挂起函数的执行 ======================================= yield语句形式 yield 1 yield的表达式形式 x=yield next(g) g.send('xxx') 示例 def deco(func): def wrapper(*args,**k

Python基础第十天——yield的表达式形式的应用、面向过程编程、内置函数

鸡汤: 首先,我一定要怀着一颗感恩的心,感谢这个世界上与我接触的人,不管你们对我是关心.是帮助.是冷漠.甚至是厌恶,我都感谢你们. 因为关心和帮助让我感受到了对爱的希望, 因为冷漠和厌恶让我感悟到了人生的残酷, 让恨的怒气和爱的力量化作一股永生不灭的的动力,使我在这条未知的人生道路上   继续写下新的篇章. --奔跑吧小白 一.yield的表达式形式的应用 send():具有传值和next的效果.先暂停的位置传值,再next生成器 send(None):表示不传值,只有next的效果,相当于直接

Python基础------生成器表达式形式、面向过程编程、内置函数部分

生成器表达式形式 直接上代码 1 # yield的表达式形式 2 def foo(): 3 print('starting') 4 while True: 5 x=yield #默认返回为空,实际上为x=yield None 6 print('value',x) 7 g=foo() 8 print(g.__next__()) #停到yield位置,生成器初始化,遇到yield返回一个None 9 print('---分割线君---') 10 print(g.send(1)) #传值给yield,

python基础之生成器表达式形式、面向过程编程、内置函数部分

生成器表达式形式 直接上代码 1 # yield的表达式形式 2 def foo(): 3 print('starting') 4 while True: 5 x=yield #默认返回为空,实际上为x=yield None 6 print('value',x) 7 g=foo() 8 print(g.__next__()) #停到yield位置,生成器初始化,遇到yield返回一个None 9 print('---分割线君---') 10 print(g.send(1)) #传值给yield,

叠加多个装饰器、yield表达式、三元表达式、生成式、函数的递归

叠加多个装饰器 # 一.叠加多个装饰器的加载.运行分析(了解***) # def deco1(func1): # func1 = wrapper2的内存地址# def wrapper1(*args,**kwargs):# print('正在运行===>deco1.wrapper1')# res1=func1(*args,**kwargs)# return res1# return wrapper1 # def deco2(func2): # func2 = wrapper3的内存地址# def