Sil*_*ker 4 python debugging parsing python-3.x pdb
我在python3.6中编写了一个解析器; 我仍在尽可能地简化它,同时仍然产生错误:
def tokenize(expr):
for i in expr:
try:
yield int(i)
except ValueError:
yield i
def push_on_stream(obj, stream):
yield obj
yield from stream
class OpenBracket:
"just a token value, could have used Ellipsis"
pass
def parse_toks(tokstream):
result = []
leading_brak = False
for tok in tokstream:
if tok == OpenBracket:
leading_brak = True
elif tok == '(':
result.append(parse_toks(
push_on_stream(OpenBracket, tokstream)))
elif tok == ')':
if not leading_brak:
raise SyntaxError("Very bad ')'.")
break
else:
result.append(tok)
return sum(result)
def test(expr="12(34)21"):
tokens = tokenize(expr)
print( parse_toks(tokens) )
print(list(tokens))
test()
Run Code Online (Sandbox Code Playgroud)
这个例子很简单; 效果应该是添加字符串中的所有数字,包括括号中的数字.
tokenize()函数产生令牌,parse_tok()函数解析令牌流.如果它遇到一个开括号,它会递归(将OpenBracket推送到令牌流),这应该具有将括号中的数字作为单独的表达式处理,解析它并将结果添加到结果堆栈的效果.
当我解析代码时,例如在表达式"1(2)3"上,它立即在close括号后结束,返回3,实际上令牌流似乎已经结束.
然而,当我使用pdb运行它,并在parse_tok中的循环内设置断点时,我可以在处理')'时仔细步骤,程序正确返回6.
我认为这个bug与push_on_stream()中令牌流的屈服有关.
这是解释器中的错误吗?如果是这样有一个很好的解决方法?
我为python-3.6编写了它,但我也在python-3.7上在不同的机器上测试了它,结果相同.
你的push_on_stream工作方式并不像你认为的那样.
看看,当push_on_stream回收生成器时,Python会调用close生成器,它会GeneratorExit生成一个生成器,以确保运行任何finally块和__exit__方法.由于push_on_stream使用yield from对底层发生器,如果push_on_stream是悬浮在yield from,这将引发一个GeneratorExit 在底层tokenize发生器.
这会立即终止令牌流.在pdb中,某些东西导致push_on_stream生成器无法收集,从而阻止了这种影响.
| 归档时间: |
|
| 查看次数: |
66 次 |
| 最近记录: |