PEP 342 (通过增强型发电机进行协作)在生成器对象中添加了一个throw()方法,该方法允许调用方在生成器内引发异常(就像由yield表达式抛出的那样)。
我想知道这个特性的用例是什么。
发布于 2012-07-14 20:13:07
假设我使用生成器来处理向数据库添加信息;我使用它来存储网络接收到的信息,通过使用生成器,我可以在实际接收数据时高效地完成这个任务,而其他事情则不然。
因此,我的生成器首先打开一个数据库连接,每次发送它时,它都会添加一行:
def add_to_database(connection_string):
db = mydatabaselibrary.connect(connection_string)
cursor = db.cursor()
while True:
row = yield
cursor.execute('INSERT INTO mytable VALUES(?, ?, ?)', row)这一切都很好;每次我.send()我的数据时,它都会插入一行。
但是如果我的数据库是事务性的呢?当将数据提交到数据库时,如何向这个生成器发出信号?什么时候中止交易?此外,它保存着与数据库的开放连接,也许我有时希望它关闭该连接以回收资源。
这就是.throw()方法出现的原因;使用.throw(),我可以在该方法中引发异常,以指示某些情况:
def add_to_database(connection_string):
db = mydatabaselibrary.connect(connection_string)
cursor = db.cursor()
try:
while True:
try:
row = yield
cursor.execute('INSERT INTO mytable VALUES(?, ?, ?)', row)
except CommitException:
cursor.execute('COMMIT')
except AbortException:
cursor.execute('ABORT')
finally:
cursor.execute('ABORT')
db.close()生成器上的.close()方法在本质上也是如此;它使用GeneratorExit异常和.throw()组合来关闭正在运行的生成器。
所有这一切都是协同工作方式的重要基础;协同机制本质上是生成器,加上一些额外的语法使编写协同线更容易、更清晰。但是在引擎盖下,它们仍然建立在同样的屈服和发送的基础上。当您并行运行多个协同线时,您需要一种方法来干净地退出这些协同线,如果其中之一失败了,请举一个例子。
发布于 2012-07-17 18:47:27
在我看来,throw()方法是有用的,有很多原因。
throw()方法,调用方可以向生成器发出必须纠正的异常情况的信号。)如果生成器能够引发异常,并被调用方截获,则也应该有可能发生相反的情况。yield语句,调用方可能不知道生成器的内部状态。通过抛出异常,就可以将生成器重置到已知的状态,或者实现更复杂的流控制,这对于单独使用next()、send()和close()来说要麻烦得多。重置内部状态的示例:
def gen():
try:
yield 10
print("State1")
yield 20
print("State2")
yield 30
print("State3")
except:
#Reset back to State1!
yield gen()
g = gen()
print(next(g))
print(next(g))
g = g.throw(ValueError) #state of g has been reset
print(next(g))
>>10
>>State1
>>20
>>10询问用例可能会使人产生误解:对于每个用例,您可以生成一个反示例,而不需要throw()方法,而且讨论将永远持续下去.
发布于 2014-12-06 19:45:49
一个用例是在发生异常时,在堆栈跟踪中包含有关生成器内部状态的信息--这些信息对调用者来说是不可见的。
例如,假设我们有一个生成器,如下所示,我们想要的内部状态是生成器的当前索引号:
def gen_items():
for i, item in enumerate(["", "foo", "", "foo", "bad"]):
if not item:
continue
try:
yield item
except Exception:
raise Exception("error during index: %d" % i)以下代码不足以触发额外的异常处理:
# Stack trace includes only: "ValueError: bad value"
for item in gen_items():
if item == "bad":
raise ValueError("bad value")但是,以下代码确实提供了内部状态:
# Stack trace also includes: "Exception: error during index: 4"
gen = item_generator()
for item in gen:
if item == "bad":
gen.throw(ValueError, "bad value")https://stackoverflow.com/questions/11485591
复制相似问题