rjk*_*lan 28 debugging wolfram-mathematica
我有一个名为myUsefulFunctions.m的Mathematica文件,其中包含一个名为mySuperUsefulFunction的函数.假设我在笔记本中调用mySuperUsefulFunction并收到以下错误:
Part::pspec: Part specification #1 is neither an integer nor a list of integers. >>
Run Code Online (Sandbox Code Playgroud)
有没有办法在myUsefulFunctions.m中找到发生此错误的行?
Leo*_*rin 21
除了其他建议,这里有一个帮助我几次的功能:
ClearAll[debug];
SetAttributes[debug, HoldAll];
debug[code_] :=
Internal`InheritedBlock[{Message},
Module[{inMessage},
Unprotect[Message];
Message[args___] /; ! MatchQ[First[Hold[args]], _$Off] :=
Block[{inMessage = True},
Print[{
Shallow /@ Replace[#, HoldForm[f_[___]] :> HoldForm[f], 1],
Style[Map[Short, Last[#], {2}], Red]
} &@Drop[Drop[Stack[_], -7], 4]
];
Message[args];
Throw[$Failed, Message];
] /; ! TrueQ[inMessage];
Protect[Message];
];
Catch[StackComplete[code], Message]]
Run Code Online (Sandbox Code Playgroud)
这基本上重新定义Message了执行堆栈并以易于理解的形式打印被调用函数的名称,以及导致错误消息的最终调用以及错误消息本身.之后,我们通过异常退出执行,不会生成令人困惑的错误消息链.
以下是来自@ Mr.Wizard的答案的例子:
In[211]:= debug[myFunc2[Range@10,#1]]
During evaluation of In[211]:=
{{myFunc2,Pick,myFunc1,Part},{1,2,3,4,5,6,7,8,9,10}[[#1]]}
During evaluation of In[211]:= Part::pspec: Part specification #1 is neither
an integer nor a list of integers. >>
Out[211]= $Failed
Run Code Online (Sandbox Code Playgroud)
(在笔记本中,有问题的函数调用被涂成红色).这允许人们快速查看导致问题的函数调用链.
这是另一个例子:我们构造一个自定义gatherBy函数,根据另一个"标记"列表收集列表中的元素,该标记应该与原始列表的长度相同:
listSplit[x_, lengths_] :=
MapThread[Take[x, {##}] &, {Most[#], Rest[#] - 1}] &@
Accumulate[Prepend[lengths, 1]];
gatherBy[lst_, flst_] :=
listSplit[lst[[Ordering[flst]]], (Sort@Tally[flst])[[All, 2]]];
Run Code Online (Sandbox Code Playgroud)
例如:
In[212]:= gatherBy[Range[10],{1,1,2,3,2,4,5,5,4,1}]
Out[212]= {{1,2,10},{3,5},{4},{6,9},{7,8}}
Run Code Online (Sandbox Code Playgroud)
因为我故意将所有类型检出,所以带有错误类型参数的调用将导致一系列令人讨厌的错误消息:
In[213]:= gatherBy[Range[10],Range[15]]//Short
During evaluation of In[206]:= Part::partw: Part 11 of {1,2,3,4,5,6,7,8,9,10} does not exist. >>
(* 4 more messages here *)
Out[213]//Short= {{1,2,3,4,5,6,7,8,9,10},<<14>>}
Run Code Online (Sandbox Code Playgroud)
使用debug,我们可以很快看到错误:
In[214]:= debug[gatherBy[Range[10],Range[15]]]
During evaluation of In[214]:=
{{gatherBy,listSplit,Part},
{1,2,3,4,5,6,7,8,9,10}[[Ordering[{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}]]]}
During evaluation of In[214]:= Part::partw: Part 11 of {1,2,3,4,5,6,7,8,9,10} does not exist. >>
Out[214]= $Failed
Run Code Online (Sandbox Code Playgroud)
gatherBy[Range[10], a]使用一些符号a来调用 是另一个环绕debug有帮助的例子.
其他建议的方法更系统,可能更普遍推荐,但这个方法很容易应用,并且导致通常更容易理解的结果(例如,与输出相比Trace,这并不总是易于阅读).但是,我并没有经常使用它来保证它始终有效.
Sjo*_*ies 20
除了Workbench中的调试器之外,Mathematica中还内置了一个调试器.您可以在"评估"菜单中找到它.它没有很好的记录,而且很难/非传统地使它发挥作用.以下是如何使用它的分步说明:
假设您在评估菜单中打开了调试器,您的窗口栏将指示它是一个调试会话,您将有一些调试器调色板.

现在选择要作为断点的多行,然后单击"选择中断"文本.断点将以红色轮廓标记.

并按Shift-return运行代码,并准备稍微失望:它不起作用.您似乎无法在线路级别定义断点.它必须处于功能级别.此外,MMA对您可以使用的功能相当挑剔.该Print功能显然不起作用.然而,Integrate在这个例子中,但你必须选择它的头和两个支架,使该断点.如果你已经这样做,然后你执行代码块,你得到这个:

断点以绿色突出显示,控制面板中的一些其他选项可用于控制进一步的程序流,并且堆栈窗口中有表达式.其余部分或多或少类似于标准调试器.请注意,您可以在集成中嵌套断点,例如Cos.对于可以具有深层嵌套结构的语言,这是必不可少的.
另一种选择是David Bailey的调试器.他在他的网站上提供免费的调试器DebugTrace.我自己没有尝试过,但我知道David是一位非常有能力的Mathematica专家,所以我相信它一定很好.
Mr.*_*ard 17
我不知道在文件中找到该行的方法,我认为该行没有错误.
但是Trace,您可以使用相关函数来查看评估链中错误发生的位置.
例:
myFunc1[x_, y_] := x[[y]]
myFunc2[a_List, n_] := Pick[a, a, myFunc1[a, n]]
myFunc2[Range@10, #1]
During evaluation of In[4]:= Part::pspec: Part specification #1 is neither an integer nor a list of integers. >>
Run Code Online (Sandbox Code Playgroud)
用Trace:
myFunc2[Range@10, #1] // Trace // Column
{Range[10], {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}
myFunc2[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, #1]
Pick[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, myFunc1[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, #1]]
{myFunc1[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, #1], {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}[[#1]], {Message[Part::pspec, #1], {MakeBoxes[Part::pspec: Part specification #1 is neither an integer nor a list of integers. >>, StandardForm], RowBox[{RowBox[{Part, ::, "pspec"}], : , "\!\(\*StyleBox[\"\\\"Part specification \\\"\", \"MT\"]\)\!\(\*StyleBox[\!\(#1\), \"MT\"]\)\!\(\*StyleBox[\"\\\" is neither an integer nor a list of integers.\\\"\", \"MT\"]\) \!\(\*ButtonBox[\">>\", ButtonStyle->\"Link\", ButtonFrame->None, ButtonData:>\"paclet:ref/message/General/pspec\", ButtonNote -> \"Part::pspec\"]\)"}]}, Null}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}[[#1]]}
Run Code Online (Sandbox Code Playgroud)
你可以看到就在Message[Part::pspec, #1]调用之前,这导致了很长时间的格式化,我们有:
{myFunc1[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, #1], {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}[[#1]]
这表明myFunc1[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, #1]被调用,这导致评估{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}[[#1]]显然是错误的.
请查看此问题及其答案,以便更方便地使用Trace:
小智 8
您可以在那里使用WolframWorkbench和调试器:
http://www.wolfram.com/broadcast/screencasts/workbench/debugging/
然后,您可以设置断点并逐步执行代码.
| 归档时间: |
|
| 查看次数: |
6867 次 |
| 最近记录: |