Pyparsing:更改所有解析器元素的默认调试操作
Pyparsing: changing default debug actions for all parser elements
我想通过添加缩进来提高 pyparsing 调试输出的可读性。例如,而不是这个:
Match part at loc 0(1,1)
Match subpart1 at loc 0(1,1)
Match subsubpart1 at loc 0(1,1)
Matched subsubpart1 at loc 10(2,1) -> ...
Matched subpart1 at loc 20(3,1) -> ...
Match subpart2 at loc 20(3,1)
Match subsubpart2 at loc 20(3,1)
Matched subsubpart2 at loc 30(4,1) -> ...
Matched subpart2 at loc 40(5,1) -> ...
Matched part at loc 50(6,1) -> ...
我想让它像这样缩进,以便更好地理解解析过程中发生的事情:
Match part at loc 0(1,1)
Match subpart1 at loc 0(1,1)
Match subsubpart1 at loc 0(1,1)
Matched subsubpart1 at loc 10(2,1) -> ...
Matched subpart1 at loc 20(3,1) -> ...
Match subpart2 at loc 20(3,1)
Match subsubpart2 at loc 20(3,1)
Matched subsubpart2 at loc 30(4,1) -> ...
Matched subpart2 at loc 40(5,1) -> ...
Matched part at loc 50(6,1) -> ...
所以在 pyparsing.py 中,我只是将 _defaultStartDebugAction
、_defaultSuccessDebugAction
和 _defaultExceptionDebugAction
更改为:
pos = -1
def _defaultStartDebugAction( instring, loc, expr ):
global pos
pos = pos + 1
print ("\t" * pos + ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))
def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
print ("\t" * pos + "Matched " + _ustr(expr) + " -> " + str(toks.asList()))
global pos
pos = pos - 1
def _defaultExceptionDebugAction( instring, loc, expr, exc ):
print ("\t" * pos + "Exception raised:" + _ustr(exc))
global pos
pos = pos - 1
(我只是将 pos
表达式和 "\t" * pos
添加到输出以获得我想要的结果)
但是,我不喜欢直接篡改pyparsing 库。另一方面,我不想在我定义的每个解析器元素上都使用 .setDebugActions
方法,我希望它们都使用我修改过的默认调试操作。
有没有一种方法可以实现这一点而不必直接篡改 pyparsing.py 库?
谢谢!
Python 模块就像任何其他 Python 对象一样,您可以使用标准 Python 函数装饰方法来操作它们的符号。通常称为 "monkeypatching",这些可以完全通过您自己的代码完成,而无需修改实际的库源。
实现此更改的最简单方法是覆盖符号。在你的代码中,写:
import pyparsing
# have to import _ustr explicitly, since it does not get pulled in with '*' import
_ustr = pyparsing._ustr
pos = -1
def defaultStartDebugAction_with_indent( instring, loc, expr ):
global pos
pos = pos + 1
print ("\t" * pos + ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))
def defaultSuccessDebugAction_with_indent( instring, startloc, endloc, expr, toks ):
global pos
print ("\t" * pos + "Matched " + _ustr(expr) + " -> " + str(toks.asList()))
pos = pos - 1
def defaultExceptionDebugAction_with_indent( instring, loc, expr, exc ):
global pos
print ("\t" * pos + "Exception raised:" + _ustr(exc))
pos = pos - 1
pyparsing._defaultStartDebugAction = defaultStartDebugAction_with_indent
pyparsing._defaultSuccessDebugAction = defaultSuccessDebugAction_with_indent
pyparsing._defaultExceptionDebugAction = defaultExceptionDebugAction_with_indent
或者更简洁的版本是用您的代码作为装饰器包装原始方法:
pos = -1
def incr_pos(fn):
def _inner(*args):
global pos
pos += 1
print ("\t" * pos , end="")
return fn(*args)
return _inner
def decr_pos(fn):
def _inner(*args):
global pos
print ("\t" * pos , end="")
pos -= 1
return fn(*args)
return _inner
import pyparsing
pyparsing._defaultStartDebugAction = incr_pos(pyparsing._defaultStartDebugAction)
pyparsing._defaultSuccessDebugAction = decr_pos(pyparsing._defaultSuccessDebugAction)
pyparsing._defaultExceptionDebugAction = decr_pos(pyparsing._defaultExceptionDebugAction)
这样,如果您更新 pyparsing 并且原始代码发生更改,您的 monkeypatch 将获得更新,而无需修改原始方法的副本。
为了使您的意图更加清晰,并避免重复这些函数名称 (DRY),这将替换最后 3 行:
def monkeypatch_decorate(module, name, deco_fn):
setattr(module, name, deco_fn(getattr(module, name)))
monkeypatch_decorate(pyparsing, "_defaultStartDebugAction", incr_pos)
monkeypatch_decorate(pyparsing, "_defaultSuccessDebugAction", decr_pos)
monkeypatch_decorate(pyparsing, "_defaultExceptionDebugAction", decr_pos)
我想通过添加缩进来提高 pyparsing 调试输出的可读性。例如,而不是这个:
Match part at loc 0(1,1)
Match subpart1 at loc 0(1,1)
Match subsubpart1 at loc 0(1,1)
Matched subsubpart1 at loc 10(2,1) -> ...
Matched subpart1 at loc 20(3,1) -> ...
Match subpart2 at loc 20(3,1)
Match subsubpart2 at loc 20(3,1)
Matched subsubpart2 at loc 30(4,1) -> ...
Matched subpart2 at loc 40(5,1) -> ...
Matched part at loc 50(6,1) -> ...
我想让它像这样缩进,以便更好地理解解析过程中发生的事情:
Match part at loc 0(1,1)
Match subpart1 at loc 0(1,1)
Match subsubpart1 at loc 0(1,1)
Matched subsubpart1 at loc 10(2,1) -> ...
Matched subpart1 at loc 20(3,1) -> ...
Match subpart2 at loc 20(3,1)
Match subsubpart2 at loc 20(3,1)
Matched subsubpart2 at loc 30(4,1) -> ...
Matched subpart2 at loc 40(5,1) -> ...
Matched part at loc 50(6,1) -> ...
所以在 pyparsing.py 中,我只是将 _defaultStartDebugAction
、_defaultSuccessDebugAction
和 _defaultExceptionDebugAction
更改为:
pos = -1
def _defaultStartDebugAction( instring, loc, expr ):
global pos
pos = pos + 1
print ("\t" * pos + ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))
def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
print ("\t" * pos + "Matched " + _ustr(expr) + " -> " + str(toks.asList()))
global pos
pos = pos - 1
def _defaultExceptionDebugAction( instring, loc, expr, exc ):
print ("\t" * pos + "Exception raised:" + _ustr(exc))
global pos
pos = pos - 1
(我只是将 pos
表达式和 "\t" * pos
添加到输出以获得我想要的结果)
但是,我不喜欢直接篡改pyparsing 库。另一方面,我不想在我定义的每个解析器元素上都使用 .setDebugActions
方法,我希望它们都使用我修改过的默认调试操作。
有没有一种方法可以实现这一点而不必直接篡改 pyparsing.py 库?
谢谢!
Python 模块就像任何其他 Python 对象一样,您可以使用标准 Python 函数装饰方法来操作它们的符号。通常称为 "monkeypatching",这些可以完全通过您自己的代码完成,而无需修改实际的库源。
实现此更改的最简单方法是覆盖符号。在你的代码中,写:
import pyparsing
# have to import _ustr explicitly, since it does not get pulled in with '*' import
_ustr = pyparsing._ustr
pos = -1
def defaultStartDebugAction_with_indent( instring, loc, expr ):
global pos
pos = pos + 1
print ("\t" * pos + ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))
def defaultSuccessDebugAction_with_indent( instring, startloc, endloc, expr, toks ):
global pos
print ("\t" * pos + "Matched " + _ustr(expr) + " -> " + str(toks.asList()))
pos = pos - 1
def defaultExceptionDebugAction_with_indent( instring, loc, expr, exc ):
global pos
print ("\t" * pos + "Exception raised:" + _ustr(exc))
pos = pos - 1
pyparsing._defaultStartDebugAction = defaultStartDebugAction_with_indent
pyparsing._defaultSuccessDebugAction = defaultSuccessDebugAction_with_indent
pyparsing._defaultExceptionDebugAction = defaultExceptionDebugAction_with_indent
或者更简洁的版本是用您的代码作为装饰器包装原始方法:
pos = -1
def incr_pos(fn):
def _inner(*args):
global pos
pos += 1
print ("\t" * pos , end="")
return fn(*args)
return _inner
def decr_pos(fn):
def _inner(*args):
global pos
print ("\t" * pos , end="")
pos -= 1
return fn(*args)
return _inner
import pyparsing
pyparsing._defaultStartDebugAction = incr_pos(pyparsing._defaultStartDebugAction)
pyparsing._defaultSuccessDebugAction = decr_pos(pyparsing._defaultSuccessDebugAction)
pyparsing._defaultExceptionDebugAction = decr_pos(pyparsing._defaultExceptionDebugAction)
这样,如果您更新 pyparsing 并且原始代码发生更改,您的 monkeypatch 将获得更新,而无需修改原始方法的副本。
为了使您的意图更加清晰,并避免重复这些函数名称 (DRY),这将替换最后 3 行:
def monkeypatch_decorate(module, name, deco_fn):
setattr(module, name, deco_fn(getattr(module, name)))
monkeypatch_decorate(pyparsing, "_defaultStartDebugAction", incr_pos)
monkeypatch_decorate(pyparsing, "_defaultSuccessDebugAction", decr_pos)
monkeypatch_decorate(pyparsing, "_defaultExceptionDebugAction", decr_pos)