以 Python 代码片段为例理解 __getattribute__ 和 pdb.set_trace()
understanding __getattribute__ and pdb.set_trace() with a Python code snippet as an example
我已经阅读了 this on SO 这样的问题,我相信我理解使用 __getattribute__
的危险。不过最近接了一个别人的项目,需要做一些修改。我认为了解一个项目的最好方法是跟踪它——所以我插入了 pdb.set_trace() 然后我按下了 "n\r\n"——但是程序没有执行到下一行并等待新的input 而是继续执行直到结束。经过搜索,我认为是 __getattribute__
的误用导致了问题,但我不知道为什么。我将代码简化为以下内容:
class TestAttribute(object):
"""docstring for TestAttribute"""
def __init__(self, is_testing=False):
super(TestAttribute, self).__init__()
self.is_testing = is_testing
def __getattribute__(self, name):
# print(name)
try:
# the line below will trigger the recursion error
if self.is_testing:
name = name.upper()
return super(TestAttribute, self).__getattribute__(name)
except AttributeError:
return None
except Exception:
# this line is added by me to see the output
import traceback; traceback.print_exc();
return None
def __getitem__(self, name):
return self.__getattribute__(name)
def __setitem__(self, name, val):
return self.__setattr__(name, val)
def __setattr__(self, name, val):
# so this func will be called in __init__ and will
# enter __getattribute__
if self.is_testing:
name = name.lower()
super(TestAttribute, self).__setattr__(name, val)
if __name__ == '__main__':
ttt = TestAttribute()
import pdb; pdb.set_trace()
ttt.k = 1
print('test done')
print('test done again')
print('test done again')
print('test done again')
输出如下:
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
if self.is_testing:
File "test_getattribute.py", line 16, in __getattribute__
import traceback; traceback.print_exc();
File "/usr/lib/python2.7/traceback.py", line 232, in print_exc
print_exception(etype, value, tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 125, in print_exception
print_tb(tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 69, in print_tb
line = linecache.getline(filename, lineno, f.f_globals)
File "/home/jgu/repos/.venv/lib/python2.7/linecache.py", line 14, in getline
lines = getlines(filename, module_globals)
File "/home/jgu/repos/.venv/lib/python2.7/linecache.py", line 40, in getlines
return updatecache(filename, module_globals)
RuntimeError: maximum recursion depth exceeded
> /home/jgu/repos/dat_cs/test_getattribute.py(34)<module>()
-> ttt.k = 1
(Pdb) n
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
if self.is_testing:
File "test_getattribute.py", line 7, in __getattribute__
def __getattribute__(self, name):
File "/usr/lib/python2.7/bdb.py", line 50, in trace_dispatch
return self.dispatch_call(frame, arg)
File "/usr/lib/python2.7/bdb.py", line 76, in dispatch_call
if not (self.stop_here(frame) or self.break_anywhere(frame)):
File "/usr/lib/python2.7/bdb.py", line 147, in break_anywhere
return self.canonic(frame.f_code.co_filename) in self.breaks
File "/usr/lib/python2.7/bdb.py", line 29, in canonic
if filename == "<" + filename[1:-1] + ">":
RuntimeError: maximum recursion depth exceeded in cmp
test done
test done again
test done again
test done again
如您所见,我只按了"n\r\n",执行一直持续到程序结束。
还有一个小问题,如果我 运行 没有 pdb,我会看到这个输出:
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
if self.is_testing:
File "test_getattribute.py", line 16, in __getattribute__
import traceback; traceback.print_exc();
File "/usr/lib/python2.7/traceback.py", line 232, in print_exc
print_exception(etype, value, tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 125, in print_exception
print_tb(tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 69, in print_tb
line = linecache.getline(filename, lineno, f.f_globals)
File "/home/jgu/repos/.venv/lib/python2.7/linecache.py", line 14, in getline
lines = getlines(filename, module_globals)
File "/home/jgu/repos/.venv/lib/python2.7/linecache.py", line 40, in getlines
return updatecache(filename, module_globals)
RuntimeError: maximum recursion depth exceeded
Traceback (most recent call last):
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
if self.is_testing:
File "test_getattribute.py", line 16, in __getattribute__
import traceback; traceback.print_exc();
File "/usr/lib/python2.7/traceback.py", line 232, in print_exc
print_exception(etype, value, tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 125, in print_exception
print_tb(tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 67, in print_tb
' File "%s", line %d, in %s' % (filename, lineno, name))
RuntimeError: <unprintable RuntimeError object>
test done
test done again
test done again
test done again
所以第二个错误没有打印正确,这是为什么?
编辑: 我不是在问为什么会出现递归错误。我相信我对那部分很清楚——所以请先理解我的问题。谢谢
pdb 使用 sys.settrace
设置跟踪函数来完成它的工作。传播到跟踪函数之外的任何异常都会禁用它。 RuntimeError 发生在 trace 函数内部,一旦发生,基本上会关闭 pdb。
我已经阅读了 this on SO 这样的问题,我相信我理解使用 __getattribute__
的危险。不过最近接了一个别人的项目,需要做一些修改。我认为了解一个项目的最好方法是跟踪它——所以我插入了 pdb.set_trace() 然后我按下了 "n\r\n"——但是程序没有执行到下一行并等待新的input 而是继续执行直到结束。经过搜索,我认为是 __getattribute__
的误用导致了问题,但我不知道为什么。我将代码简化为以下内容:
class TestAttribute(object):
"""docstring for TestAttribute"""
def __init__(self, is_testing=False):
super(TestAttribute, self).__init__()
self.is_testing = is_testing
def __getattribute__(self, name):
# print(name)
try:
# the line below will trigger the recursion error
if self.is_testing:
name = name.upper()
return super(TestAttribute, self).__getattribute__(name)
except AttributeError:
return None
except Exception:
# this line is added by me to see the output
import traceback; traceback.print_exc();
return None
def __getitem__(self, name):
return self.__getattribute__(name)
def __setitem__(self, name, val):
return self.__setattr__(name, val)
def __setattr__(self, name, val):
# so this func will be called in __init__ and will
# enter __getattribute__
if self.is_testing:
name = name.lower()
super(TestAttribute, self).__setattr__(name, val)
if __name__ == '__main__':
ttt = TestAttribute()
import pdb; pdb.set_trace()
ttt.k = 1
print('test done')
print('test done again')
print('test done again')
print('test done again')
输出如下:
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
if self.is_testing:
File "test_getattribute.py", line 16, in __getattribute__
import traceback; traceback.print_exc();
File "/usr/lib/python2.7/traceback.py", line 232, in print_exc
print_exception(etype, value, tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 125, in print_exception
print_tb(tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 69, in print_tb
line = linecache.getline(filename, lineno, f.f_globals)
File "/home/jgu/repos/.venv/lib/python2.7/linecache.py", line 14, in getline
lines = getlines(filename, module_globals)
File "/home/jgu/repos/.venv/lib/python2.7/linecache.py", line 40, in getlines
return updatecache(filename, module_globals)
RuntimeError: maximum recursion depth exceeded
> /home/jgu/repos/dat_cs/test_getattribute.py(34)<module>()
-> ttt.k = 1
(Pdb) n
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
if self.is_testing:
File "test_getattribute.py", line 7, in __getattribute__
def __getattribute__(self, name):
File "/usr/lib/python2.7/bdb.py", line 50, in trace_dispatch
return self.dispatch_call(frame, arg)
File "/usr/lib/python2.7/bdb.py", line 76, in dispatch_call
if not (self.stop_here(frame) or self.break_anywhere(frame)):
File "/usr/lib/python2.7/bdb.py", line 147, in break_anywhere
return self.canonic(frame.f_code.co_filename) in self.breaks
File "/usr/lib/python2.7/bdb.py", line 29, in canonic
if filename == "<" + filename[1:-1] + ">":
RuntimeError: maximum recursion depth exceeded in cmp
test done
test done again
test done again
test done again
如您所见,我只按了"n\r\n",执行一直持续到程序结束。
还有一个小问题,如果我 运行 没有 pdb,我会看到这个输出:
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
if self.is_testing:
File "test_getattribute.py", line 16, in __getattribute__
import traceback; traceback.print_exc();
File "/usr/lib/python2.7/traceback.py", line 232, in print_exc
print_exception(etype, value, tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 125, in print_exception
print_tb(tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 69, in print_tb
line = linecache.getline(filename, lineno, f.f_globals)
File "/home/jgu/repos/.venv/lib/python2.7/linecache.py", line 14, in getline
lines = getlines(filename, module_globals)
File "/home/jgu/repos/.venv/lib/python2.7/linecache.py", line 40, in getlines
return updatecache(filename, module_globals)
RuntimeError: maximum recursion depth exceeded
Traceback (most recent call last):
Traceback (most recent call last):
File "test_getattribute.py", line 10, in __getattribute__
if self.is_testing:
File "test_getattribute.py", line 16, in __getattribute__
import traceback; traceback.print_exc();
File "/usr/lib/python2.7/traceback.py", line 232, in print_exc
print_exception(etype, value, tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 125, in print_exception
print_tb(tb, limit, file)
File "/usr/lib/python2.7/traceback.py", line 67, in print_tb
' File "%s", line %d, in %s' % (filename, lineno, name))
RuntimeError: <unprintable RuntimeError object>
test done
test done again
test done again
test done again
所以第二个错误没有打印正确,这是为什么?
编辑: 我不是在问为什么会出现递归错误。我相信我对那部分很清楚——所以请先理解我的问题。谢谢
pdb 使用 sys.settrace
设置跟踪函数来完成它的工作。传播到跟踪函数之外的任何异常都会禁用它。 RuntimeError 发生在 trace 函数内部,一旦发生,基本上会关闭 pdb。