Nik*_*kiC 50 python generator throw
PEP 342(通过增强型生成器的协程)throw()向生成器对象添加了一个方法,它允许调用者在生成器内引发异常(就好像它是由yield表达式抛出的).
我想知道这个功能的用例是什么.
Mar*_*ers 58
假设我使用生成器来处理向数据库添加信息的问题.我使用它来存储网络接收的信息,并且通过使用生成器,我可以在实际接收数据时有效地执行此操作,否则执行其他操作.
所以,我的生成器首先打开一个数据库连接,每次你发送一些东西,它都会添加一行:
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)
Run Code Online (Sandbox Code Playgroud)
这一切都很好,很好; 每次.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()
Run Code Online (Sandbox Code Playgroud)
.close()发电机上的方法基本上是一样的; 它使用GeneratorExit异常结合.throw()来关闭正在运行的生成器.
所有这些都是协同程序工作的重要基础; 协同程序本质上是生成器,以及一些额外的语法,使协同写入更容易和更清晰.但在引擎盖下,它们仍然建立在相同的屈服和发送上.当你并行运行多个协同程序时,你需要一种方法来干净地退出这些协同程序,如果其中一个失败,只是举一个例子.
Ste*_*o M 10
在我看来,该throw()方法有很多原因.
对称性:没有强有力的理由只应在调用者处理异常条件,而不是在生成器函数中处理.(假设数据库中的生成器读取值返回错误值,并假设只有调用者知道该值是坏的.使用该throw()方法,调用者可以向生成器发信号通知存在必须纠正的异常情况. )如果发生器可以引发由调用者拦截的异常,则也应该是相反的.
灵活性:生成器函数可能有多个yield语句,调用者可能不知道生成器的内部状态.通过抛出异常,可以复位发生器到已知状态,或者为了实现这将与方法更多一些更复杂的流程控制next(),send(),close()独自一人.
询问用例可能会产生误导:对于每个用例,您都可以在不需要throw()方法的情况下生成反例,并且讨论将永远持续下去......
一个用例是在发生异常时在堆栈跟踪中包含有关生成器内部状态的信息——否则调用者将看不到这些信息。
例如,假设我们有一个如下所示的生成器,其中我们想要的内部状态是生成器的当前索引号:
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)
Run Code Online (Sandbox Code Playgroud)
以下代码不足以触发额外的异常处理:
# Stack trace includes only: "ValueError: bad value"
for item in gen_items():
if item == "bad":
raise ValueError("bad value")
Run Code Online (Sandbox Code Playgroud)
但是,以下代码确实提供了内部状态:
# Stack trace also includes: "Exception: error during index: 4"
gen = item_generator()
for item in gen:
if item == "bad":
gen.throw(ValueError, "bad value")
Run Code Online (Sandbox Code Playgroud)