R中的错误处理:在函数错误时访问函数内的已知对象

时间:2017-11-20 08:29:40

标签: r error-handling

这是一个示例函数,假设我无法编辑它。

ToolbarItems

myfun <- function(){ x <- 1 ; stop( "error here" ) } 发生时,我如何访问对象stop()以查看它是什么?

不确定我是否应该使用类似的内容,或者我需要与x相关的内容,或者如果不改变dump.frames

这是不可能的
myfun()

我正在寻找类似于此行为的内容,但需要在没有withCallingHandlers( myfun() , error = function(e){ print( e ) } )

的情况下执行此操作
myfun()

对于我的用例,我无法更改myfun <- function(){ on.exit( print( x ) ) ; x <- 1 ; stop( "error here" ) } myfun() ,因为大约有50个函数,但我想在错误发生时知道每个函数中一致命名的对象

谢谢!

4 个答案:

答案 0 :(得分:6)

选项1:

当然,您可以使用browser()逐步执行这些功能,但这可能会耗费您所需的时间。

选项2

虽然你说你无法改变myfun()的原因是&#34;因为大约有50个函数&#34;,这并不是一个不可逾越的障碍。 R的一个强大功能是它可以编辑自己的功能。所以我们可以像这样添加on.exit函数调用:

body(myfun) <- as.call(c(as.name("{"), expression(on.exit(print(x))), body(myfun)))

我们可以将它包装在一个方便的功能中,它不会像这样改变原来的功能:

print.on.exit = function(f, ...){
  body(f) <- as.call(c(as.name("{"), expression(on.exit(print(x))), body(f)))
  f(...)
}

print.on.exit(myfun)

答案 1 :(得分:2)

这是使用trace执行此操作的方法。我也使用purr::walk,因为它是沉默的,但您可以使用sapply代替相同的效果。

首先让我们定义3个函数,因为你有50个函数:

myfun1 <- function(){ x <- 1 ; stop( "error here" ) }
myfun2 <- function(){ x <- 2 ; banana(2) }
myfun3 <- function(){ x <- 3 ; x <- "potatoe" + x }

myfun1() # Error in myfun1() : error here
myfun2() # Error in myfun2() : could not find function "banana"
myfun3() # Error in "potatoe" + x : non-numeric argument to binary operator

然后将它们的名字放在一个向量中,只需应用这个代码,只要退出函数就会打印x

funs <- c("myfun1","myfun2","myfun3")
purrr::walk(funs,trace,exit = quote(print( x )))

myfun1() 
# Error in myfun1() : error here
# Tracing myfun1() on exit 
# [1] 1

myfun2()
# Error in myfun2() : could not find function "banana"
# Tracing myfun2() on exit 
# [1] 2

myfun3()
# Error in "potatoe" + x : non-numeric argument to binary operator
# Tracing myfun3() on exit 
# [1] 3

然后恢复正常:

purrr::walk(funs,untrace)

修改

使用上述方法,即使没有错误,也会打印x

myfun4 <- function(){ x <- 4 ; TRUE }
trace(myfun4, exit = quote(print( x )))
myfun4()
Tracing myfun4() on exit 
[1] 4
[1] TRUE

要仅在出错时打印x,您可以使用以下代码,我将print参数设置为FALSE以获得更轻的显示,并使其比打印更清晰错误时的值是x:

untrace(myfun4)
funs <- c("myfun1","myfun2","myfun3","myfun4") 
purrr::walk(funs,trace, print=FALSE,exit=quote(
  if(exists(".Traceback") && .Traceback[[length(.Traceback)]] == sys.calls()[[1]]){
    message("x at time of error:")
    print(x)}))

myfun3()
# Error in "potatoe" + x : non-numeric argument to binary operator
# x at time of error:
# [1] 3

myfun4()
# [1] TRUE

答案 2 :(得分:1)

我尝试回答但是我不确定你想要什么,你能编辑你的函数来添加on.exit吗? :

mylistofstate<-list()
fn <- function() {
  x <-1
    on.exit(mylistofstate["x"]<<-x, add=TRUE)
    stop()
}
fn()
 > Error in fn() : 
mylistofstate
 > $x
 >[1] 1

答案 3 :(得分:1)

此方法允许访问myfun的执行环境,而无需重写:

checkX <- function () { print(get("x", envir=parent.frame())) }
checkFun <- function (f) {
  eval(parse(text=c("on.exit(checkX())", deparse(body(f)))))
}

您可以checkX执行您需要的操作,通过parent.frame()调用可以完全访问函数的执行上下文。

myfun <- function(){ x <- 1 ; stop( "error here" ) }
checkFun(myfun)

要使用参数处理函数,可以使用以下函数包装旧函数:

wrapFun <- function (f) {
  eval(parse(text=c(deparse(args(f))[1], "{", "on.exit(checkX())", deparse(body(f)), "}")))
}

用你想要的参数调用它:

myfun2 <- function(y){ x <- y + 1 ; stop( "error here" ) }
wrapFun(myfun2)(3)