打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
R语言代码调试



      Norman Matloff PeteSalzman在其著作《TheArt of Debugging, withGDB,DDD,Eclipse》中曾说过,确认原则是调试的本质。程序员编写程序是为实现特定目的,而一个程序可以由许多目的组成,调试是确认某些目的是否达到了,如果未能达到目的,那么便可通过在调试中查看变量,发现问题症结,进而解决问题。

    在R中进行debug有几种不同方式,你如果使用诸如Rstudio等图形软件,调试代码很容易,所有的调试都在图形界面下完成,你只需要根据需求在图形界面下点击相应选项来进行断点设置、单步执行、查看变量等操作,查找问题症结。但如果在命令行界面下调试R代码,那就得要借助于一些特别的调试工具。R的基础软件包base中包含了一些基本的调试工具,当然CRAN中也有一些其它优秀的调试工具。

    对于一般用户来说,掌握base中的基本调试工具就能满足大部分需求,下面介绍R基本软件包base中的调试工具的使用方法(也包含setBreakpoint(),其位于utils包中)   

   由于在启动和关闭调试中需要用到部分调试命令,这里就先介绍进入调试模式后需要用到的一些基本命令。


    1.基本调试命令

    在进入dedbug调试状态后,命令提示符从>变为Browse[d]>(d表示函数调用链的深度),可以通过一些基本的命令来进行控制:

  • n(表示next): 告诉R执行下一行代码,并且执行完后马上暂停,实际就是一行一行地执行代码。相当于C语言开发工具Turbo C中的trace into
  • c(表示continue):表示会执行若干条语句。若当前处在循环中,这一步会执行完整个循环,若当前处在函数内但又不再循环中,则会执行完当前函数。相当于C语言开发工具Turbo C中的step over
  • where: 输出一份栈跟踪路径,显示到达当前位置的过程中函数的调用序列。
  • Q: 退出brower,返回R的主交互模式。
  • 任意R命令: 即使在调试状态browser中,依然处于R的交互模式中,所以你可以用任意R命令。



    2启动和关闭调试

    R的核心调试工具由browser构成,通过browser,你可以逐行运行代码,并在运行过程中进行检查,查看变量。在调试代码时,我们首先要让程序进入调试状态,有下列几种方式可以实现。


    2.1 在代码中的指定位置加入browser()

   开启调试:

      在R源文件中的指定位置插入函数browser(),保存源文件,运行源程序,程序一旦运行到browser()处,将会自动进入debug状态。

   取消调试:

      但当用户完成调试后,需要手动删除源文件中的browser()函数,否则每次运行到browser()位置都会进入debug状态。

       temp_test.R:

           (PS:此文件在下面会多次用到,所以贴出来,但后续用到时已经删除了browser()) 

  1. countsum <- function(count)  
  2. {  
  3.     sum <- 0  
  4.     for (i in 1:count)  
  5.     {  
  6.         sum <- sum + i  
  7.     }  
  8.     browser()  
  9.     return (sum)  
  10. }  
  11. results <- countsum(100)  
  12. print(results)  
  13.    
    运行之后:

  1. > source("temp_test.R")  
  2. Called from: countsum(100)  
  3. Browse[1]>  


    2.2调用debug()

    R的调试工具是针对单个函数的,由于拥有函数式编程的特性,R的每一个运算符,实际上也是函数(关于R函数,可参考这里),这里所说的函数不包括一般的运算符。

   开启调试:

      执行命令debug(fun)

            fun指函数名,这样每次调用函数fun()都会进入调试状态。

    取消调试:

       执行命令undebug(fun)

       再次调用函数fun()将不会进入调试状态。

   如下例所示: 

  1. > source("temp_test.R")  
  2. [1] 5050  
  3. > debug(countsum)  
  4. > countsum(10)  
  5. debugging in: countsum(10)  
  6. debug at temp_test.R#1: {  
  7.     sum <- 0  
  8.     for (i in 1:count) {  
  9.         sum <- sum + i  
  10.     }  
  11.     return(sum)  
  12. }  
  13. Browse[2]> n  
  14. debug at temp_test.R#2: sum <- 0  
  15. Browse[2]> n  
  16. debug at temp_test.R#3: for (i in 1:count) {  
  17.     sum <- sum + i  
  18. }  
  19. Browse[2]> sum  
  20. [1] 0  
  21. Browse[2]> c  
  22. exiting from: countsum(10)  
  23. [1] 55  
 

    2.3调用debugonce()

     debug()的调用方式一样,区别在于:debugonce()只会在设置之后的第一次调用时进入调试状态且只只进入一次,而debug()可以进入无限多次直到通过undebug()取消调试。


    2.4用函数trace()进行跟踪

    trace(fun,tracer)

    fun表示需要跟踪或者取消跟踪的函数名;racer表示跟踪的对象,可以是某个函数,也可以是函数中的某个表达式。

    开启调试:

      执行命令trace(fun,tracer)

      每次调用函数fun(),都会显示表达式的值,或者对函数进行某些操作。

    取消调试:

      执行命令untrace(fun)

      取消对某个函数的跟踪。

   如下例所示:

  1. > source("temp_test.R")  
  2. [1] 5050  
  3. > trace(countsum,sum)  
  4. [1] "countsum"  
  5. > countsum(10)  
  6. Tracing countsum(10) on entry  
  7. [1] 55  
  8. > untrace(countsum)  
  9. > trace(countsum,browser())  
  10. Called from:methods::.TraceWithMethods(countsum, browser(), where =<environment>)  
  11. Browse[1]> Q  
  12. > rm(list = ls())  
  13. > source("temp_test.R")  
  14. [1] 5050  
  15. > trace(countsum,sum)  
  16. [1] "countsum"  
  17. > countsum(10)  
  18. Tracing countsum(10) on entry  
  19. [1] 55  
  20. > untrace(countsum)  
  21. > trace(countsum,browser)  
  22. [1] "countsum"  
  23. > countsum(20)  
  24. Tracing countsum(20) on entry  
  25. Called from: eval(expr, envir, enclos)  
  26. Browse[1]> n  
  27. debug: {  
  28. sum <- 0  
  29. for (i in 1:count) {  
  30. sum <- sum + i  
  31. }  
  32. return(sum)  
  33. }  
  34. Browse[2]> c  
  35. [1] 210  


    2.5.设置断点setBreakpoint()

    setBreakpoint()位于utils包中,R版本需要>=2.10

    setBreakpoint(filename,linenumber)

  表示会在源文件filename的第linenumber行设置断点,但是实际上是通过函数来进行设置的,这点需要注意,即只有所设置的断点处于文件中的某个函数内才是有效的。此函数可以用在debug调试状态中,在单步调试过程中,当设置了断点后,可以让程序直接运行到到断点处,这在调试过程中很有用处。

    开启调试:

      执行命令setBreakpoint(filename,linenumber)

      然后再执行代码,当代码运行到断点处即进入调试状态。

    取消调试:

      执行命令untrace(fun)

          fun表示函数名Breakpoint要设在函数内才有效,所以应当通过函数来取消断点setBreakpoint()是通过调用trace()发挥作用的。

   如下例所示:

  1. >source("temp_test.R")  
  2. [1]5050  
  3. >setBreakpoint("temp_test.R",3)  
  4. /home/sheng/WinD/test/temp_test.R#3:  
  5. countsumstep 3 in <environment: R_GlobalEnv>  
  6. >countsum(20)  
  7. temp_test.R#3  
  8. Calledfrom: countsum(20)  
  9. Browse[1]>n  
  10. debug:for (i in 1:count) {  
  11.     sum<- sum + i  
  12. }  
  13. Browse[2]>where  
  14. where1: countsum(20)  
  15. Browse[2]>sum  
  16. [1]0  
  17. Browse[2]>c  
  18. [1]210  



参考:

[1] Norman Matloff著,陈堰平等译.R语言编程艺术.机械工业出版社,2013-05






本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Trace 和Debug WriteLine 方法
VC程序调试技术--遥远的地平线
VC++一些常用调试方法
VC++程序调试 - VC++ - 开发语言 - 程序员之家
C#调试从入门到精通(1) - 51CTO.COM
Anaconda中的Spyder进行断点调试
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服