2012-01-02 49 views
7

在我正在编写的模块中,我有(开发和测试阶段)大量的Print["Messages"]。我有两个问题:mathematica中的消息生成

  1. 打印此类“调试”消息的最佳做法是什么?
  2. 有没有办法调用模块,以便打印消息NOT?例如,当从另一个模块调用模块时,我不希望看到第一个模块的输出。
+2

在第8节中,还有'Assert',它的作用类似于打印信息在测试失败,并可以关闭 – 2011-02-25 21:30:32

+0

@Verbeia是的,没错......我只是认为这两个问题是如此接近,这将是有益的,让他们合并,并拥有所有在同一个地方回答。无论是合并到这一个还是相反,它并不重要... – Szabolcs 2012-01-02 11:25:46

+0

@Szololcs在聊天中看到消息 – Verbeia 2012-01-02 11:39:36

回答

12

我想一直保持与$前缀全局变量和函数没有前缀,所以我会写:

debugPrint[args___] := $debugPrintFunction[args] 

$debugPrintFunction = Print[##] & 

然后,你可以使用debugPrint酷似你使用Print现在。当你想摆脱调试信息时,你只需取消设置变量:

$debugPrintFunction = . 

这样做有一些优点。其中之一是,你可以使用Block来开启和关闭本地调试:

In[1]:= foo[x_] := (debugPrint[x]; x+1) 

In[2]:= foo[3] 
3 
Out[2]= 4 

In[3]:= Block[{$debugPrintFunction}, foo[3] 
Out[3]= 4 

你甚至可以在本地使$debugPrintFunction做别的事情,比如Sow值一个Reap回暖,或直接调试消息其他地方,例如

strm = OpenWrite["your/log/path/here", InputForm]; 
Block[{$debugPrintFunction = Write[strm, ##]}, 
    foo[3]]; 
Close[strm]; 

明智地使用,由Block提供的动态范围界定允许在一个相对安全和可控的方式使用全局变量。

+0

好的招数,我用尽了票,但是只要袋子补充了,我就立刻赞成 – 2011-02-25 20:49:49

+0

太棒了,非常感谢你 – 2011-02-25 21:19:37

8

我的旧代码使用像Pillsy描述的方法。

最近我更多使用头通常没有任何规则,如:

... 
debugPrint[expr] 
... 

再有第二个功能:

Attributes[PrintDebug]={HoldAll} 

PrintDebug[expr_] := Block[{debugPrint = Print}, expr] 

然后当我想看调试输出我可以在输入处打印PrintDebug:

PrintDebug[MyFunction[1,2,3]] 

或更频繁地作为

MyFunction[1,2,3] // PrintDebug 

因为我发现后缀表单更容易添加/删除,并更好地将焦点留在主函数上。

0

对我来说,由于M没有内置的调试器,所以我在调试时浪费了50%的时间,如果有调试器,可能会保存它。我的开发代码中有50%是Print语句,因为如果没有这些语句,我会迷失方向,发现错误来自哪里。 (这也很糟糕,因为代码中的打印消息太多,使得很难在某个时候看到算法,它阻碍了它,但无法删除它,因为我稍后可能需要它。

我发现像M这样强大而灵活的计算工具仍然具有相对不太先进的开发环境,这让我感到惊奇。当我使用Matlab时,使用调试器需要几秒钟才能找到错误。

有人可能会说使用Workbench进行调试。我试图用来调试一个Manipulate演示,我无法弄清楚。使用太复杂。 M需要一个简单易用的调试器内置(在笔记本本身中,不是一个单独的程序)和行号!

好吧,鉴于上述介绍:),这是我做我自己的回答您的问题:

  1. 有不同程度的调试信息。粗略水平和详细水平。粗糙级别仅在进入功能和存在功能时才打印消息。

  2. 我在用户界面上有一个按钮用于打开/关闭调试(如果你正在做基于UI的程序,否则它将在代码中)。

  3. 使用一个单独的调试功能,其中调试消息在打印之前经过。在那里,您可以在打印前为每条消息添加时间戳(也可以控制是否希望消息从一个位置进入文本文件)。其余的代码,只是调用这个调试功能与消息打印。我现在打印所有内容,而不是当前的笔记本。

  4. 每条调试消息都具有调用它的函数名称。

  5. 如果要控制模块级别的调试,我只需在模块内创建一个本地调试标志,并在每次调试该特定模块时打开/关闭该模块。此本地调试标志接管全局调试标志的设置。这样,如果需要,我可以只调试一个模块,而不是其他代码。

还有很多其他的方法来定制所有这些。但是我发现,如果我尽早花更多时间来创建一个良好的调试消息系统,它可以帮助您在需要时查找错误。

以下是一些有用的链接

http://reference.wolfram.com/mathematica/guide/TuningAndDebugging.html

工作台调试器(如果你能弄清楚如何使用调试操作和动态,请让我知道)

http://www.wolfram.com/products/workbench/features/debug.html

+3

只是为了澄清,Mathematica *确实*具有内置调试器,您可以在其中设置断点,步入代码等等。虽然使用起来有点不方便,但它在那里。 '评估 - >调试器' – Szabolcs 2012-01-02 10:02:11

+0

@Szabolcs,是的,我知道那个。但它实际上可用吗?我花了2个小时就可以在那天,甚至不知道如何使用它来调试我的笔记本操作。最后,我放弃了,回到打印消息:) – Nasser 2012-01-02 10:16:29

+2

许多人可能会遇到这个问题和答案,我认为这是误导他们说没有调试器。确实我没有太多用处,而且这不是非常实用,但我确实偶尔使用它。 – Szabolcs 2012-01-02 10:49:30

3

另一个可能性:

debugPrint::msg = "Debug message: `1`";  
debugPrint[msg_] := Message[debugPrint::msg, msg] 

使用这样的功能:

debugPrint["hello"] 

关闭或打开的消息是这样的:

Off[debugPrint::msg] 

On[debugPrint::msg] 
6

我通常安装verbosing选项进入我的功能,即可以开启/关闭,如果有必要的调试。请注意,通过在函数内指定详细的默认值,您可以控制是否打印信息。

In[5]:= func1[arg_, opts___] := Module[{verbose}, 
    verbose = Verbose /. {opts} /. {Verbose -> True}; 
    If[verbose, Print["Verbosing function1: arg is ", arg]]; 
    arg 
    ]; 

func2[arg_, opts___] := Module[{verbose}, 
    verbose = Verbose /. {opts} /. {Verbose -> False}; 
    func1[arg, Verbose -> verbose] 
    ]; 

In[7]:= func1[123] 

During evaluation of In[7]:= Verbosing function1: arg is 123 

Out[7]= 123 

In[8]:= func2[456] 

Out[8]= 456 

In[9]:= func1[123, Verbose -> False] 

Out[9]= 123 

In[10]:= func2[456, Verbose -> True] 

During evaluation of In[10]:= Verbosing function1: arg is 456 

Out[10]= 456 

当然可以阐述本实施例中是符合的Mathematica的编程标准(例如添加Options[func1, Verbose -> ...]标头,然后从该函数内访问选项,但在这里这不是点。

+1

您可以找到有助于以下构造__verbose &&打印[“Verbosing function1:arg is”,arg] __,而不是IF。 – 2012-01-02 12:37:32

+0

这是一个聪明的捷径,节省了我很多的括号匹配,谢谢! – 2012-01-03 12:11:05