1、包含yield的函数
假如你看到某个函数包含了yield,这意味着这个函数已经是一个Generator,它的执行会和其他普通的函数有很多不同。比如下面的简单的函数:
可以看到,调用h()之后,print 语句并没有执行!这就是yield,那么,如何让print 语句执行呢?这就是后面要讨论的问题,通过后面的讨论和学习,就会明白yield的工作原理了。
In [52]: def h():
....: print ‘To be brave‘
....: yield 5
....:
In [53]: h()
Out[53]: <generator object h at 0x2a6f370>
In [54]: def h():
print ‘To be brave‘
In [55]:
In [55]: h()
To be brave
2、yield是一个表达式
m = yield 5
表达式(yield 5)的返回值将赋值给m,所以,认为 m = 5 是错误的。那么如何获取(yield 5)的返回值呢?需要用到后面要介绍的send(msg)方法。
4、send(msg) 与 next()
其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做
c.next() 和 c.send(None) 作用是一样的。
In [78]: def h():
print ‘Wen Chuan‘,
m = yield 5 # Fighting!
print‘m is %s:‘ % m
d = yield 12
print ‘We are together!‘
....:
In [79]: c=h()
In [80]: c.next()
Wen ChuanOut[80]: 5
In [81]: c.next()
m is None:
Out[81]: 12
In [82]: c=h()
In [83]: c.next() #相当于c.send(None)
Wen ChuanOut[83]: 5
In [84]: c.send(‘fighting‘) #(yield 5)表达式被赋予了‘Fighting!‘
m is fighting:
Out[84]: 12
需要提醒的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值。
5. send(msg) 与 next()的返回值
send(msg) 和 next()是有返回值的,它们的返回值很特殊,返回的是下一个yield表达式的参数。比如yield 5,则返回 5 。到这里,是不是明白了一些什么东西?本文第一个例子中,通过for i in alist 遍历 Generator,其实是每次都调用了alist.Next(),而每次alist.Next()的返回值正是yield的参数,即我们开始认为被压进去的东东。我们再延续上面的例子:
In [91]: def h():
print ‘Wen Chuan‘,
m = yield 5 # Fighting!
print m
d = yield 12
print ‘We are together!‘
....:
In [92]: c=h()
In [93]: m=c.next() #m 获取了yield 5 的参数值 5
Wen Chuan
In [94]: d=c.send(‘fighting‘) #d 获取了yield 12 的参数值12
fighting --- 表达式(yield 12)的值m为fighting
In [96]: print ‘we will never forget the date‘,m,‘.‘,d
we will never forget the date 5 . 12
《提高你的Python: 解释‘yield’和‘Generators(生成器)’》
https://www.oschina.net/translate/improve-your-python-yield-and-generators-explained
yield就是专门给生成器用的return(加上点小魔法)。
下面是一个简单的生成器函数:
In [3]: def simple_generator_function():
...: yield 1
...: yield 2
...: yield 3
...:
这里有两个简单的方法来使用它:
In [4]: for value in simple_generator_function():
...: print(value)
...:
1
2
3
In [5]: our_generator = simple_generator_function()
In [6]: next(our_generator)
Out[6]: 1
In [7]: next(our_generator)
Out[7]: 2
In [8]: next(our_generator)
Out[8]: 3
In [1]: def is_prime(number):
...: if number > 1:
...: if number == 2:
...: return True
...: if number % 2 == 0:
...: return False
...: for current in range(3, int(math.sqrt(number) + 1), 2):
...: if number % current == 0:
...: return False
...: return True
...: return False
...:
In [2]: def get_primes(number):
...: while True:
...: if is_prime(number):
...: yield number
...: number += 1
...:
yield执行流程分析
调用get_primes
In [30]: def solve_number_10():
....: # She *is* working on Project Euler #10, I knew it!
....: total = 2
....: for next_prime in get_primes(3):
....: if next_prime < 2000000:
....: total += next_prime
....: else:
....: print(total)
....: return
....:
我们来看一下solve_number_10的for循环中对get_primes的调用,观察一下前几个元素是如何创建的有助于我们的理解。当for循环从get_primes请求第一个值时,我们进入get_primes,这时与进入普通函数没有区别。
接下来,回到insolve_number_10:
这次,进入get_primes时并没有从开头执行,我们从第5行继续执行,也就是上次离开的地方。
In [2]: def get_primes(number):
...: while True:
...: if is_prime(number):
...: yield number
...: number += 1 # <<<<<<<<<<
...:
最关键的是,number还保持我们上次调用yield时的值(例如3)。记住,yield会将值传给next()的调用方,同时还会保存生成器函数的“状态”。接下来,number加到4,回到while循环的开始处,然后继续增加直到得到下一个素数(5)。我们再一次把number的值通过yield返回给solve_number_10的for循环。这个周期会一直执行,直到for循环结束(得到的素数大于2,000,000)。
class AppApiHandler(BaseHandler):
executor = ThreadPoolExecutor(max_workers=20) ---- 最多20个线程
@run_on_executor
def run_app_api(self, app, func, args):
role = self.get_current_user()
args[‘APP_USER_ROLE‘] = role
try:
module = importlib.import_module(‘apps.%s.api‘ % app) --- 装载模块‘icbc_auto_platform\apps\n5k_upgrade\api’
app_func = getattr(module, func) --- 返回api中的函数对象
return app_func(**args) --- args返回api函数结果
except ImportError:
raise
原文地址:http://f1yinsky.blog.51cto.com/12568071/1916516