我正在使用yield from
,但是我不知道while
对yield
的影响。如果我将yield from
放入while
循环中,则效果很好,但是同时取消循环时会发生异常。
final_result = {}
def sales_sum(pro_name):
total = 0
nums = []
while True:
x = yield
print(pro_name+" Sales volume: ", x)
if not x:
break
total += x
nums.append(x)
return total, nums
def middle(key):
while True:
final_result[key] = yield from sales_sum(key)
def middle2(key):
final_result[key] = yield from sales_sum(key)
def main(fun):
data_sets = { "A": [1200, 1500], "B": [28,55,98]}
for key, data_set in data_sets.items():
m = fun(key)
m.send(None)
for value in data_set:
m.send(value)
m.send(None)
if __name__ == '__main__':
main(middle) # work well
main(middle2) # StopIteration
我希望main(middle2)
和main(middle)
一样好,但是有一个StopIteration
例外。
答案 0 :(得分:1)
program server;
{$mode delphi}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes , Windows , Winsock , SysUtils
{ you can add units after this };
procedure SendFullnameTest();
var
MyData:WSADATA;
result:Integer;
s:TSocket;
SendBuf:Array[0..31] of AnsiChar;
clientservice:sockaddr_in;
BytesSent:Integer;
begin
try
result:= WSAStartup(MAKEWORD (2,2), MyData);
if result = NO_ERROR then
begin
s := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if s <> INVALID_SOCKET then
begin
clientservice.sin_family := AF_INET;
clientservice.sin_addr.s_addr := inet_addr('127.0.0.1');
clientservice.sin_port := htons(8080);
if connect(s,clientservice,sizeof(clientservice)) <> SOCKET_ERROR then
begin
sendbuf := 'I am a Sent message';
bytesSent := send(s,sendbuf,Length(sendbuf),0);
writeln('Bytes send: ',bytesSent);
end else
writeln('Failed to connect');;
end else
writeln('Error at Socket: ',WSAGetLastError);;
end else
writeln('Error at WSAStartup');
finally
Writeln(SysErrorMessage(GetLastError));
WSACleanUp;
Readln;
end;
end;
begin
SendFullnameTest();
ReadLn;
end.
是一个有限迭代器。 sales_sum
仅在其上迭代一次; middle2
尝试对其进行多次迭代。
答案 1 :(得分:1)
StopIteration
中意外的main
异常的原因是您的m.send(None)
调用导致middle2
生成器用尽(在子生成器{{1}之后}响应收到的falsey值而跳出循环。发电机耗尽时,它会升高sales_sum
。通常,这是不可见的,因为您在StopIteration
循环中使用了迭代器,但是在这种情况下,它将破坏您的代码。
有几种方法可以解决此问题。一种是对for
使用两个参数的调用,而不是使用next
:
m.send(None)
这与next(m, None)
的作用相同,但是具有抑制m.send(None)
的附加好处。请注意,对StopIteration
的调用中的None
与next
中的调用并不完全相同。对于迭代器用尽的情况,它是默认的返回值,而不是发送的值(使用send
时始终为None
)。
另一种方法是更改next
,以使其在middle2
生成器执行时不会结束。您可以在末尾添加一个额外的sales_sum
语句,以便在其子生成器返回时对yield
进行赋值后,它最后一次产生控制权。
最后的想法是将final_result
替换为m.send(None)
。这将需要对m.close()
进行一些更改,因为final_result
调用将向生成器中抛出close
异常。如果您希望的话,可以将其用作完成操作的信号,而不用寻找虚假的值:
GeneratorExit
有了此更改,def sales_sum(pro_name):
total = 0
nums = []
while True:
try:
x = yield
except GeneratorExit:
return total, nums
print(pro_name+" Sales volume: ", x)
total += x
nums.append(x)
无需进行任何修改。