我有一段代码需要处理大量数据,并且需要相当长的时间(大约 4 小时 - 我想过夜运行它)。库(selenium)中使用的一种方法在被上诉时会在大约 10% 的情况下返回错误,并且需要重新运行代码/单元格(与 Web scraped 的网站不一致)。
我找到了一种重新启动块的方法,而不会丢失处理数据的进度,但是,我必须手动检查错误并在发生错误时重新运行单元。我的问题是,这可以在不丢失局部变量的情况下自动完成吗?
代码的简化版本:
代码单元格 1:
#code
n = 0
代码单元 2 - 可能会返回错误:
for i in list[n:]:
n += 1
#code
method_that can return an error
#code
有没有办法重新启动第二个代码单元而不丢失存储的变量?
只要内核未重新启动,在单元生命周期内创建的任何变量都会保留在那里,即使该行在中途出错。这意味着您可以从技术上注册一个 IPython 异常处理程序来修复错误并继续重新运行单元直到它正常工作。
至于实际重新运行单元:虽然“_X”变量在单元完成运行之前不会更新,但所有输入都会添加到全局列表中 -
In[]
- 无论它们是否真正完成。
将这两者结合起来意味着您可以“从技术上”做到这一点,但这并不是万无一失的。如果您希望它在末尾打印最初应该打印的内容,则必须以某种方式从 exec
调用外部打印结果,这是相当困难的。我能想到的就是将单元格文本放入函数中,插入返回值,将该函数调用分配给全局,然后在
exec
调用之外打印全局。但是,由于 Python 在其块中使用缩进而不是符号,因此您必须重新格式化单元格以遵循规范,并且查找要输出的表达式的开始或结束位置并非易事。这是我的 SymPy 计算器会话中的一个示例,它将任何未定义的变量用法转换为符号:
from IPython.core.ultratb import AutoFormattedTB
# initialize the formatter for making the tracebacks into strings
itb = AutoFormattedTB(mode = 'Plain', tb_offset = 1)
findNameFromNameError = r"'([^']*)'"
from IPython.display import display
def undefNamesBecomeSymbols(self, etype, evalue, tb, tb_offset=None):
if isinstance(evalue.name, str) and evalue.name.isalpha(): # makes sure it's a real name to be defined and not a reference like "_4"
# Turn the cell's input into a code block that can be executed at once
split = In[-1].split('\n')
cellBlockCall = "def _undef_out():\n\t" + ("\n\t".join(split)) + "\nundef_placeholder = _undef_out()"
symbolToCreate = evalue.name
# avoid getting stuck in an infinite loop
for i in range(0, 100):
try:
# create the undefined variable as a symbol with that name
exec(f'{symbolToCreate} = Symbol("{symbolToCreate}")', globals())
exec(cellBlockCall, globals()) # "rerun" the cell
display(undef_placeholder) # print the cell's output
return None # don't return a traceback
except NameError as err: # if the exec call throws another exception, just keep iterating
var_name = re.findall(findNameFromNameError, str(err))[0]
symbolToCreate = var_name
# if we don't run or we go too long, return the structured traceback the error handler expects
stb = itb.structured_traceback(etype, evalue, tb)
return itb.stb2text(stb)
# register the custom error handler with IPython
get_ipython().set_custom_exc((NameError,), undefNamesBecomeSymbols)