【问题标题】:R: on.exit - use returned value without knowing its nameR:on.exit - 在不知道其名称的情况下使用返回值
【发布时间】:2015-03-25 17:32:16
【问题描述】:

我有以下功能。除了函数中的第一个代码块之外,我无法以任何方式更改函数。
在这个简单的示例中,我想显示在返回对象上应用一些函数。
关键是函数返回的变量名称可能会有所不同,我无法猜测。
显然我也不能将f 函数包装到{ x <- f(); myfun(x); x } 中。
在我的on.exit 调用中,下面的.Last.value 表示f 函数要返回的值。

f <- function(param){
  # the only code I know - start
  on.exit(if("character" %in% class(.Last.value)) message(print(.Last.value)) else message(class(.Last.value)))
  # the only code I know - end

  # real processing of f()

  a <- "aaa"
  "somethiiiing"
  if(param==1L) return(a)

  b <- 5L
  "somethiiiing"
  if(param==2L) return(b)

  "somethiiiing"
  return(32)
}
f(1L)
# function
# [1] "aaa"
f(2L)
# aaa
# [1] 5
f(3L)
# integer
# [1] 32

上面带有.Last.value 的代码似乎在工作有滞后(所以实际上不工作)而且.Last.value 可能不是要走的路,因为我想使用值很少像if(fun0(x)) fun1(x) else fun2(x) 这样的时间,因为返回值可能是一个大对象,所以将它复制到一边也是不好的方法。
有什么方法可以使用on.exit 或任何其他可以帮助我在不知道结果变量名称的情况下在f 函数结果上运行我的函数的函数?

【问题讨论】:

  • 为什么不能包装函数来获取输出?或者为什么只能更改函数的第一个块?这些是非常奇怪的限制。我以前研究过这个,不可能以完全通用的方式从函数内部获取函数返回值(我希望我能找到上一个问题,但我认为大部分讨论都发生在没有出现的 cmets 中可搜索)。
  • @MrFlick,我将我的代码注入到我想要审核的处理函数中。它们在外部包中,由其他包中的其他功能使用。是的,我知道这个问题要求很高,可能无法回答。 This 是相关的,但解决方案是包装成对我没有帮助的新功能。
  • 我只是想建议trace(),但后来我意识到这就是the last question 想要做的。仍然可以在包命名空间内分配替换函数。如果这就是您真正想要做的事情,那么如果您有一个更合适的可重现示例会有所帮助。
  • @MrFlick,真实情况是在that call中传递[.data.table返回的值的if("data.table" %in% class(?)) nrow(?) else NA_integer_

标签: r data.table devtools


【解决方案1】:

与修改函数的方式类似,您也可以轻松地包装它。这是一个可重现的示例。

library(data.table)

append.log<-function(x) {
    cat(paste("value:",x,"\n"))
}

idx.dt <- data.table:::`[.data.table`
environment(idx.dt)<-asNamespace("data.table")

idx.wrap <- function(...) {
    x<-do.call(idx.dt, as.list(substitute(...())), envir=parent.frame())
      append.log(if(is(x, "data.table")) {
          nrow(x)
      } else { NA })
      x
}
environment(idx.wrap)<-asNamespace("data.table")

(unlockBinding)("[.data.table",asNamespace("data.table"))
assign("[.data.table",idx.wrap,envir=asNamespace("data.table"),inherits=FALSE)


dt<-data.table(a=1:10, b=seq(2, 20, by=2), c=letters[1:10])

dt[a%%2==0]

【讨论】:

  • 不错!非常感谢您的努力。这说得通!你知道这是否适合不制作任何额外的副本并且不放慢速度?我希望日志记录尽可能轻松。
  • 我应该澄清一下,仅仅因为它是可能的,我不一定推荐尝试将代码注入包命名空间中的函数。在性能方面,您必须自己进行基准测试。我无法想象这种类型的日志记录会有用或必要的情况,但这取决于你。
  • 是的,这是肮脏的方式,但有效。我将使用 CI travis 并在加载我的包后不仅测试我的包,还测试 data.table 测试。以及用例:ETL 转换步骤。
  • 查看我的全新答案 :)
【解决方案2】:

由于新功能returnValue,从 R 3.2.0 开始,这完全可以实现。 下面的工作示例。

f <- function(x, err = FALSE){
  pt <- proc.time()[[3L]]
  on.exit(message(paste("proc.time:",round(proc.time()[[3L]]-pt,4),"\nnrow:",as.integer(nrow(returnValue()))[1L])))
  Sys.sleep(0.001)
  if(err) stop("some error")
  return(x)
}
dt <- data.frame(a = 1:5, b = letters[1:5])
f(dt)
f(dt, err=T)
f(dt)
f(dt[dt$a %in% 2:3 & dt$b %in% c("c","d"),])

【讨论】:

    猜你喜欢
    • 2010-11-23
    • 2021-01-05
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 2016-11-10
    • 1970-01-01
    • 1970-01-01
    • 2014-05-08
    相关资源
    最近更新 更多