yield随想
2022年9月3日C#、Python程序中可以写yield指令,这样程序的执行权就暂时交出去了,等另一方运行完成后再回来。设当前方法为f,f可以集中处理资源创建和销毁,资源创建完成后,用yield指令把资源交给另一个方法。
C#实现如下。f为包含yield的方法,File类代表对外部资源的封装。f的方法体集中处理file.Open()和file.Close(),并在中间把可用的file传出去。在main方法中,通过某种结构调用f方法,获得了可用的file,并写出字符串。
class Program
{
static void Main(string[] args)
{
foreach (File f in f())
{
f.WriteLine("hello");
f.WriteLine("How are you?");
}
}
static IEnumerable f()
{
var file = new File();
file.Open();
yield return file;
file.Close();
}
class File { ... }
}
前面的例子浅显易懂,但是包含yield的方法这个名字有什么专业的说法吗?答案是coroutine(协程)。
Python的yeild指令更强大一点,它可以返回值。这个返回值是通过send命令传入coroutine。
def f():
yield 'f1'
s = yield 'f2'
print(f'yield return {s}')
yield 'f3'
if __name__ == '__main__':
g = f()
print(f'get {next(g)}')
print(f'get {next(g)}')
print(f'get {g.send("s2")}')
这个python程序的输出是
get f1 get f2 yield return s2 get f3
当coroutine交出执行权后,另一个程序优先执行。具体表现如下。yield ‘f1’执行后,一直执行main block,直到遇到下一个next(g)或g.send。接着,执行yield ‘f2’,注意不包括s=,直到遇到下一个next(g)或g.send。这里程序遇到g.send(“s2”)。然后执行返回至f,并运行s=,所以打印出yield return s2。
yield的数量
一个coroutine yield一次,可以实现using block;yield两次,实现try-catch block;yield三次,实现try-catch-finally block。
设coroutine为f,另一个方法为g,该程序不能写成f(g())。因为按照数学,必须先计算g,后计算f。