2012-01-02 86 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