我想处理一个 NameError
异常通过将所需的缺失变量注入到帧中,然后从上一次尝试的指令继续执行。
以下伪代码应说明我的需求。
def function():
return missing_var
try:
print function()
except NameError:
frame = inspect.trace()[-1][0]
# inject missing variable
frame.f_globals["missing_var"] = ...
# continue frame execution from last attempted instruction
exec frame.f_code from frame.f_lasti
在repl.it上阅读整个unittest
笔记
背景
代码在从属进程中运行,该进程由父进程控制。任务(函数确实)写在父级中,后者使用传递给从站 莳萝。我希望一些任务(在slave进程中运行)尝试从父进程中的外部作用域访问变量,并且我希望slave能够动态地向父进程请求这些变量。
p.s。:我不希望这种魔法在生产环境中运行。
与各种评论者所说的相反,“恢复错误”异常处理 是 在Python中可能。图书馆 fuckit.py
实施所述策略。通过在导入时重写模块的源代码来阻止压路器错误, 插入 try...except
阻止每个陈述 并吞下所有例外。那么也许你可以尝试类似的策略?
不言而喻:那个图书馆是一个笑话。不要在生产代码中使用它。
您提到您的用例是捕获对缺少名称的引用。您是否考虑过使用元编程在“智能”命名空间的上下文中运行代码,例如 defaultdict
? (这可能只是一个不好的想法 fuckit.py
。)
from collections import defaultdict
class NoMissingNamesMeta(type):
@classmethod
def __prepare__(meta, name, bases):
return defaultdict(lambda: "foo")
class MyClass(metaclass=NoMissingNamesMeta):
x = y + "bar" # y doesn't exist
>>> MyClass.x
'foobar'
NoMissingNamesMeta
是一个 元类 - 用于自定义行为的语言构造 class
声明。我们在这里使用 __prepare__
自定义字典的方法,该字典将在创建类时用作类的命名空间。因此,因为我们正在使用 defaultdict
而不是常规字典,一个其元类是的类 NoMissingNamesMeta
永远不会得到 NameError
。在创建类时引用的任何名称都将自动初始化为 "foo"
。
这种方法类似于@AndréFratelli关于手动请求来自a的延迟初始化数据的想法 Scope
目的。在制作中,我会这样做,而不是这个。元类版本需要较少的输入来编写客户端代码,但代价是更多魔法。 (想象一下你自己在两年内调试这段代码,试图理解为什么不存在的变量被动态地引入范围!)
事实证明,“恢复”异常处理技术存在问题,这就是为什么它缺少C ++和后来的语言。
你最好的选择是用一个 while
循环不恢复抛出异常的位置,而是从预定位置重复:
while True:
try:
do_something()
except NameError as e:
handle_error()
else:
break
在抛出异常后你真的无法展开堆栈,所以你必须事先处理这个问题。如果您的要求是动态生成这些变量(不建议这样做,但您似乎明白这一点),那么您必须实际请求它们。您可以为此实现一种机制(例如具有全局自定义 Scope
类实例和重写 __getitem__
,或使用类似的东西 __dir__
功能),但不是你要求它。