R語言-調試代碼

和其他語言一樣你自然可以通過print一些參數之類的方法進行debug,但是R或RStudio提供的一些代碼調試工具還是能爲你提供一些有用的嘗試。
這些工具包括:traceback、browser、debug、debugonce、trace和recover函數。

一般debug包括兩個步驟,首先是定位代碼錯誤發生的位置,然後是找出代碼發生錯誤的原因並解決

其中第一步可以藉助traceback函數來完成

traceback

traceback函數可以幫助你精確定位錯誤。很多R函數之間都會存在互相調用的情況,如何確定出錯的函數往往是個難題。

first<-function()second()
second<-function()third()
third<-function()fourth()
fourth<-function()fifth()
fifth<-function()bug()

上述函數都在調用下一個函數(除了最後一個函數)
由於bug函數不存在,運行first()將會報錯
Error in bug() : could not find function "bug"

這裏由於函數關係簡單我們很容易就知道了錯誤的原因,但很多時候你根本不知道出錯的函數是什麼地方爲什麼被調用的,此時traceback()可以看到出錯之前R函數調用的路徑,並返回一個調用棧(call stack),即調用函數的有序列表。

> traceback()
5: fifth() at #1
4: fourth() at #1
3: third() at #1
2: second() at #1
1: first()

一般來說,越靠近上層的函數出錯的可能性越大,當然這不是絕對的,比如有可能是fourth函數錯誤的使用了fifth函數才導致最終的報錯。
而且這個調用棧可以展示函數運行的過程,你可以檢查一下這和你的邏輯是否有衝突。
這個工作在RStudio中顯得更簡單,每當程序報錯RStudio都會出現下面的一個灰色方框:
這裏寫圖片描述
選擇第一個Show Traceback選項即可查看調用棧信息,而且會一直對應該錯誤,而不會想直接調用traceback函數一樣顯示最近出錯代碼的信息。
這裏寫圖片描述

當你已經找到錯誤的函數,接下來就該使用browser函數檢查一下這個函數的具體運行細節了

browser

利用browser函數可以讓R在運行過程中暫停,使你得以在命令行中鍵入命令。此時,你的任何命令的活動環境已經不再是全局環境,而改爲了處於暫停狀態下的函數的運行環境,因此你可以直接查看函數體內部的各種對象取值,並在同一環境下運行一些測試代碼。
要是用browser只需將browser()放入所需的函數體中,並將該函數保存即可,下次運行時便會在browser()處停下來。

> browser_test<-function(){
+   t1<-1
+   browser()
+   t2<-2
+ }
> browser_test()
Called from: browser_test()
Browse[1]> print(t1)  #命令提示符變爲Browse[1]>
[1] 1

此時,我們處於一個新的R模式,瀏覽器模式(browser mode)。
在RStudio的右上角可以跟直觀地查看當前環境中的對象,左上角則會突出browser()所暫停的代碼行
這裏寫圖片描述
之後你可以利用提示符窗口上方的導航按鈕實現下一步操作:
第一個按鈕是Next(下一步) 用來運行函數的下一行代碼
第二個按鈕是Continue(繼續) 用來運行函數剩餘的所有代碼,完成之後退出瀏覽器模式
第三個按鈕是Stop(停止) 他會立刻中斷並退出瀏覽器模式,不運行任何代碼
這裏寫圖片描述
這些按鈕的功能也可以通過在瀏覽器模式的提示符窗口中鍵入n、c、Q來分別實現。那麼問題出現了,如果想查看的對象名也是n、c或Q呢,該怎麼辦?此時直接鍵入這三個字母會優先處理三個按鈕的功能。此時應使用get()函數查看對應對象,在瀏覽器模式下,cont是c的同義詞,where會顯示整個調用棧,因此查看以cont和where命名的對象也要使用get()函數。

斷點

R中的斷點和絕大多數IDE中相似,都是在代碼行號的左側用鼠標單擊一下出現一個紅點,在R中即代表在該行代碼前加了browser()函數。如果是空心紅點則需要運行腳本面板右上方的Source按鈕運行腳本,空心紅點即會變爲實心。當然如果你選中了Source on Save選項,那麼每次保存時都會自動將文件source。
這裏寫圖片描述
browser和斷點是對自定義函數調試的好工具,那麼如何對一個R中已存在的含數據進行調試呢?
答案是debug函數!

debug

debug函數用於在一個已存在的的函數的起始處“添加”一個browser()語句。此時,函數處於“調試模式”,每次只要一運行該函數都會進入瀏覽器模式,需要通過undebug函數將browser()從該函數中移出,isdebugged函數用於檢查某個函數是否處於“調試”模式

> test<-function(){
+   print("hello")
+ }
+ 
#進入"調試"模式
> debug(test)
> isdebugged(test)
[1] TRUE

> test()
debugging in: test()
debug at #1: {
    print("hello")
}
Browse[2]> Q

#退出調試模式
> undebug(test)
> isdebugged(test)
[1] FALSE
> test()
[1] "hello"

如果覺得這個過程很麻煩可以使用debugonce函數代替debug函數,這樣只有第一次運行函數時會進入瀏覽器模式,當調試結束之後再次運行該函數便可以正常運行。
RStudio中可以可視化實現這個功能,那就是程序報錯之後灰色框的第二個選項:Return with Debug(以調試模式重新運行),這可以實現debugonce的功能,使錯誤的命令進入一次“調試”模式。

trace

trace可以在函數體的某一行添加某一R表達式,形如
trace("test",browser,at=4)
當你除了函數名不添加其他參數時,每次運行該函數都會在命令行中顯示:trace:<the function>
同理untrace()函數也能將函數從這個狀態中釋放出來。

> trace(print)
> print(1)
trace: print(1)
[1] 1

> untrace(print)
> print(1)
[1] 1

recover

和browser()函數一樣你可以將recover()函數放在任何你需要的地方,一旦R運行到recover函數時,它會暫停並顯示當前的調用棧信息,而且你可以選擇進入哪一個函數進入調試模式

> first()

Enter a frame number, or 0 to exit   

1: first()
2: debug_test.R#3: second()
3: #2: third()
4: debug_test.R#5: fourth()
5: debug_test.R#6: fifth()

注意這裏的顯示順序和調用棧相反
如果你覺得將recover()放入代碼中很繁瑣,可以將recover添加到R函數的全局選項中
options(error=recover)
這樣一來任何錯誤都會執行recover(),知道關閉當前R會話,或者options(error=NULL)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章