R语言代码调试

时间:2021-04-30 01:43:00



      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()) 

countsum <- function(count)
{
    sum <- 0
    for (i in 1:count)
    {
        sum <- sum + i
    }
    browser()
    return (sum)
}
results <- countsum(100)
print(results)
 
    运行之后:

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


    2.2调用debug()

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

   开启调试:

      执行命令debug(fun)

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

    取消调试:

       执行命令undebug(fun)

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

   如下例所示: 

> source("temp_test.R")
[1] 5050
> debug(countsum)
> countsum(10)
debugging in: countsum(10)
debug at temp_test.R#1: {
sum <- 0
for (i in 1:count) {
sum <- sum + i
}
return(sum)
}
Browse[2]> n
debug at temp_test.R#2: sum <- 0
Browse[2]> n
debug at temp_test.R#3: for (i in 1:count) {
sum <- sum + i
}
Browse[2]> sum
[1] 0
Browse[2]> c
exiting from: countsum(10)
[1] 55


 

    2.3调用debugonce()

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


    2.4用函数trace()进行跟踪

    trace(fun,tracer)

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

    开启调试:

      执行命令trace(fun,tracer)

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

    取消调试:

      执行命令untrace(fun)

      取消对某个函数的跟踪。

   如下例所示:

> source("temp_test.R")
[1] 5050
> trace(countsum,sum)
[1] "countsum"
> countsum(10)
Tracing countsum(10) on entry
[1] 55
> untrace(countsum)
> trace(countsum,browser())
Called from:methods::.TraceWithMethods(countsum, browser(), where =<environment>)
Browse[1]> Q
> rm(list = ls())
> source("temp_test.R")
[1] 5050
> trace(countsum,sum)
[1] "countsum"
> countsum(10)
Tracing countsum(10) on entry
[1] 55
> untrace(countsum)
> trace(countsum,browser)
[1] "countsum"
> countsum(20)
Tracing countsum(20) on entry
Called from: eval(expr, envir, enclos)
Browse[1]> n
debug: {
sum <- 0
for (i in 1:count) {
sum <- sum + i
}
return(sum)
}
Browse[2]> c
[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()发挥作用的。

   如下例所示:

>source("temp_test.R")
[1]5050
>setBreakpoint("temp_test.R",3)
/home/sheng/WinD/test/temp_test.R#3:
countsumstep 3 in <environment: R_GlobalEnv>
>countsum(20)
temp_test.R#3
Calledfrom: countsum(20)
Browse[1]>n
debug:for (i in 1:count) {
    sum<- sum + i
}
Browse[2]>where
where1: countsum(20)
Browse[2]>sum
[1]0
Browse[2]>c
[1]210



参考:

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