假设我们尝试访问不存在的属性:
>>> {'foo': 'bar'}.gte('foo') # well, I meant “get”!
Python的AttributeError
只有属性args
,其中包含一个包含已完成错误消息的字符串:'dict' object has no attribute 'gte'
将inspect
和/或traceback
模块与sys.last_traceback
一起使用,是否有办法获取实际的dict对象?
>>> offending_object = get_attributeerror_obj(sys.last_traceback)
>>> dir(offending_object)
[...
'clear',
'copy',
'fromkeys',
'get', # ah, here it is!
'items',
...]
编辑:既然猫已经不在了,我会分享我的发现和代码(请不要解决这个并提交给PyPI,请;)
创建AttributeError
here,表明显然没有对附加的原始对象的引用。
这里的代码具有相同的占位符函数:
import sys
import re
import difflib
AE_MSG_RE = re.compile(r"'(\w+)' object has no attribute '(\w+)'")
def get_attributeerror_obj(tb):
???
old_hook = sys.excepthook
def did_you_mean_hook(type, exc, tb):
old_hook(type, exc, tb)
if type is AttributeError:
match = AE_MSG_RE.match(exc.args[0])
sook = match.group(2)
raising_obj = get_attributeerror_obj(tb)
matches = difflib.get_close_matches(sook, dir(raising_obj))
if matches:
print('\n\nDid you mean?', matches[0], file=sys.stderr)
sys.excepthook = did_you_mean_hook
答案 0 :(得分:1)
这不是你想要的答案,但我很确定你不能......至少不是sys.excepthook
。这是因为引用计数在框架展开时递减,因此在调用sys.excepthook
之前对对象进行垃圾回收是完全有效的。事实上,这就是CPython中发生的事情:
import sys
class X:
def __del__(self):
print("deleting")
def error():
X().wrong
old_hook = sys.excepthook
def did_you_mean_hook(type, exc, tb):
print("Error!")
sys.excepthook = did_you_mean_hook
error()
#>>> deleting
#>>> Error!
尽管如此,情况并非总是如此。因为异常对象指向框架,如果您的代码如下所示:
def error():
x = X()
x.wrong
x
尚无法收集。 x
由框架拥有,并且框架是活动的。但是,既然我已经证明没有明确的参考这个对象,那么做什么并不明显。例如,
def error():
foo().wrong
可能有也可能没有幸存下来的对象,唯一可行的方法就是运行foo
......但即便如此,你也有副作用问题。
所以不,这是不可能的。如果你不介意任何长度,你可能最终不得不在加载时重写AST(类似于FuckIt.py)。但是你不想这样做。
我的建议是尝试使用linter来获取所有已知类及其方法的名称。您可以使用它来反向设计回溯字符串以获取类和不正确的方法,然后运行模糊匹配以查找建议。
答案 1 :(得分:1)
我成功地加入了2美分(到目前为止)尝试为DidYouMean-Python做类似的事情。
这里的诀窍在于,它几乎就是错误消息包含足够信息来推断您实际意味着什么的情况。实际上,这里真正重要的是你试图在gte
对象上调用dict
:你需要的是类型,而不是对象本身。
如果你写过{'foo': 'bar'}.get('foob')
,那么处理的情况会更加棘手,我很乐意知道是否有人有解决方案。
第一步
检查您是否正在处理AttributeError(使用挂钩的第一个参数)。
第二步
从消息中检索相关信息(使用第二个参数)。我用regexp做到了这一点。请注意,此异常可以采用多种形式,具体取决于Python的版本,您调用方法的对象等。
到目前为止,我的正则表达式为:"^'?(\w+)'? (?:object|instance) has no attribute '(\w+)'$"
第三步
获取与该类型相对应的类型对象(在您的情况下为' dict'),以便您可以在其上调用dir()
。一个肮脏的解决方案就是使用eval(type)
,但是你可以通过重用trace中的信息(钩子的第三个参数)来做得更好更干净:跟踪的最后一个元素包含发生异常的框架和该框架,类型已正确定义(作为本地类型,全局类型或内置)。
获得类型对象后,您只需要在其上调用dir()
并提取您最喜欢的建议。
如果您需要有关我所做的更多详细信息,请与我们联系。