R语言-调试代码

来源:互联网 发布:闲鱼淘宝介入支持卖家 编辑:程序博客网 时间:2024/05/16 17:20

和其他语言一样你自然可以通过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 #14: fourth() at #13: third() at #12: second() at #11: 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)