yield-based相当于Python3'yield from'委托不丢发
yield-based equivalent to Python3 'yield from' delegation without losing send
我不知道如何使用 yield
(不是 yield from
)来包装子生成器而不阻止 send() 工作。使用 yield from
允许 send() 继续使用子生成器,但它会移交控制权,您无法检查或计算通过的值。
动机:我使用 python3 生成器编写了一些流迭代,允许文件或套接字或任何通过公共 'interface' 一次读取一个字节的内容,以便解析器通过一.
为了帮助解析,我随后扩展了生成器逻辑,以便请求者可以指示流是否应在产生字节后增加其位置(字节被读取并使用),或者流是否应在产生字节后保持其位置屈服(一瞥——该字节仅被读取)。这样就可以匹配规则,然后再将流传递给 sub-parsers)。
在当前的实现中,以下任一项将从生成器中获取一个字节并增加生成器在流中的位置。
byte = stream.send(True)
byte = next(stream)
...虽然此特殊调用从生成器获取一个字节,但不会增加流中的位置。
byte = stream.send(False)
到目前为止一切顺利。我的 low-memory JSON 解析器( https://github.com/ShrimpingIt/medea ) is working well. The example at https://github.com/ShrimpingIt/medea/blob/dd0007e657cd487913c72993dcdaf0f60d8ee30e/examples/scripts/twitterValuesNamed.py 能够处理来自文件的缓存推文。
对于 HTTPS - 要从套接字获取实时推文,SSL 套接字不会在最后自动关闭。任何解析过程都会挂起等待更多数据,我想修复这个问题。
出于这个原因,我首先创建 HTTPS 流,然后从流中读取字节,处理 content-length header 并跳到末尾的“\r\n\r\n” HTTP headers,然后将正确位置的流移交给解析器。在这一点上,我知道在停止之前流现在应该提供多少内容字节。
不幸的是,我遇到了语法、表达或理解方面的问题。
直接移交给流很容易,并且保留了发送功能(允许查看字节)...
def delegatingStream():
yield from rawStream
但是,我想不出如何创建一个智能使用 contentLength 值在 contentLength 之后终止而不中断 send() 的迭代器。
我需要使用 yield
才能干预迭代器逻辑,但似乎只有 yield from
允许委托 send()。我什至无法同时使用 send 和 yield 来复制 delegatingStream() 的行为。例如,这没有相同的效果。
def relayingStream():
while True:
yield rawStream.send((yield))
避免yield from
的原因是我最终需要有一个这样的实现,(这也没有忠实地转发send())...
def terminatingStream():
contentPos = 0
while contentPos < contentLength:
increment = (yield)
yield rawStream.send(increment)
if increment is not False:
contentPos += 1
rawStream.throw(StopIteration)
知道如何在不使用 yield from
的情况下正确转发来自 send()
的值吗?
可以参考PEP 380 -- Syntax for Delegating to a Subgenerator, to see the yield from
Python equivalent, in the Formal Semantics section.
RESULT = yield from EXPR
本质上等同于:
_i = iter(EXPR)
try:
_y = next(_i)
except StopIteration as _e:
_r = _e.value
else:
while 1:
try:
_s = yield _y
except GeneratorExit as _e:
try:
_m = _i.close
except AttributeError:
pass
else:
_m()
raise _e
except BaseException as _e:
_x = sys.exc_info()
try:
_m = _i.throw
except AttributeError:
raise _e
else:
try:
_y = _m(*_x)
except StopIteration as _e:
_r = _e.value
break
else:
try:
if _s is None:
_y = next(_i)
else:
_y = _i.send(_s)
except StopIteration as _e:
_r = _e.value
break
RESULT = _r
您可以完全实施 来替换 yield from
。您可能会放弃 RESULT
处理,因为您不希望有任何处理。接下来是generator.close()
和generator.throw()
的小心处理;如果你假设这些存在,那么你可以进一步简化,并使用一些更易读的名称:
it = iter(EXPR)
try:
value = next(it)
except StopIteration:
pass
else:
while True:
try:
sent = yield value
except GeneratorExit:
it.close()
raise
except BaseException:
try:
value = it.throw(*sys.exc_info())
except StopIteration:
break
else:
try:
value = it.send(sent)
except StopIteration:
break
我还利用 generator.next()
与 generator.send(None)
在道德上等同这一事实来删除另一个测试。
将EXPR
替换为rawStream
,将整体包装成一个函数,就可以监控双向的数据流了。
我不知道如何使用 yield
(不是 yield from
)来包装子生成器而不阻止 send() 工作。使用 yield from
允许 send() 继续使用子生成器,但它会移交控制权,您无法检查或计算通过的值。
动机:我使用 python3 生成器编写了一些流迭代,允许文件或套接字或任何通过公共 'interface' 一次读取一个字节的内容,以便解析器通过一.
为了帮助解析,我随后扩展了生成器逻辑,以便请求者可以指示流是否应在产生字节后增加其位置(字节被读取并使用),或者流是否应在产生字节后保持其位置屈服(一瞥——该字节仅被读取)。这样就可以匹配规则,然后再将流传递给 sub-parsers)。
在当前的实现中,以下任一项将从生成器中获取一个字节并增加生成器在流中的位置。
byte = stream.send(True)
byte = next(stream)
...虽然此特殊调用从生成器获取一个字节,但不会增加流中的位置。
byte = stream.send(False)
到目前为止一切顺利。我的 low-memory JSON 解析器( https://github.com/ShrimpingIt/medea ) is working well. The example at https://github.com/ShrimpingIt/medea/blob/dd0007e657cd487913c72993dcdaf0f60d8ee30e/examples/scripts/twitterValuesNamed.py 能够处理来自文件的缓存推文。
对于 HTTPS - 要从套接字获取实时推文,SSL 套接字不会在最后自动关闭。任何解析过程都会挂起等待更多数据,我想修复这个问题。
出于这个原因,我首先创建 HTTPS 流,然后从流中读取字节,处理 content-length header 并跳到末尾的“\r\n\r\n” HTTP headers,然后将正确位置的流移交给解析器。在这一点上,我知道在停止之前流现在应该提供多少内容字节。
不幸的是,我遇到了语法、表达或理解方面的问题。
直接移交给流很容易,并且保留了发送功能(允许查看字节)...
def delegatingStream():
yield from rawStream
但是,我想不出如何创建一个智能使用 contentLength 值在 contentLength 之后终止而不中断 send() 的迭代器。
我需要使用 yield
才能干预迭代器逻辑,但似乎只有 yield from
允许委托 send()。我什至无法同时使用 send 和 yield 来复制 delegatingStream() 的行为。例如,这没有相同的效果。
def relayingStream():
while True:
yield rawStream.send((yield))
避免yield from
的原因是我最终需要有一个这样的实现,(这也没有忠实地转发send())...
def terminatingStream():
contentPos = 0
while contentPos < contentLength:
increment = (yield)
yield rawStream.send(increment)
if increment is not False:
contentPos += 1
rawStream.throw(StopIteration)
知道如何在不使用 yield from
的情况下正确转发来自 send()
的值吗?
可以参考PEP 380 -- Syntax for Delegating to a Subgenerator, to see the yield from
Python equivalent, in the Formal Semantics section.
RESULT = yield from EXPR
本质上等同于:
_i = iter(EXPR)
try:
_y = next(_i)
except StopIteration as _e:
_r = _e.value
else:
while 1:
try:
_s = yield _y
except GeneratorExit as _e:
try:
_m = _i.close
except AttributeError:
pass
else:
_m()
raise _e
except BaseException as _e:
_x = sys.exc_info()
try:
_m = _i.throw
except AttributeError:
raise _e
else:
try:
_y = _m(*_x)
except StopIteration as _e:
_r = _e.value
break
else:
try:
if _s is None:
_y = next(_i)
else:
_y = _i.send(_s)
except StopIteration as _e:
_r = _e.value
break
RESULT = _r
您可以完全实施 来替换 yield from
。您可能会放弃 RESULT
处理,因为您不希望有任何处理。接下来是generator.close()
和generator.throw()
的小心处理;如果你假设这些存在,那么你可以进一步简化,并使用一些更易读的名称:
it = iter(EXPR)
try:
value = next(it)
except StopIteration:
pass
else:
while True:
try:
sent = yield value
except GeneratorExit:
it.close()
raise
except BaseException:
try:
value = it.throw(*sys.exc_info())
except StopIteration:
break
else:
try:
value = it.send(sent)
except StopIteration:
break
我还利用 generator.next()
与 generator.send(None)
在道德上等同这一事实来删除另一个测试。
将EXPR
替换为rawStream
,将整体包装成一个函数,就可以监控双向的数据流了。