暂无说说

R语言-调试代码

R jiajun 4个月前 (06-16) 126次浏览 0个评论 扫描二维码

和其他语言一样你自然可以通过 print 一些参数之类的方法进行 debug,但是RRStudio 提供的一些代码调试工具还是能为你提供一些有用的尝试。
这些工具包括: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)

喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址