使用data.table作为参数在函数内使用deparse(substitute())

时间:2014-05-09 11:31:01

标签: r data.table substitution

如果我想将函数的参数解析为错误或警告,如果参数转换为函数中的data.table,则会发生奇怪的事情:

e <- data.frame(x = 1:10)
### something strange is happening
foo <- function(u) {
  u <- data.table(u)
  warning(deparse(substitute(u)), " is not a data.table")
  u
}
foo(e)

##  foo(e)
##      x
##  1:  1
##  2:  2
##  3:  3
##  4:  4
##  5:  5
##  6:  6
##  7:  7
##  8:  8
##  9:  9
## 10: 10
## Warning message:
## In foo(e) :
##   structure(list(x = 1:10), .Names = "x", row.names = c(NA, -10L), class = c("data.table", "data.frame"), .internal.selfref = <pointer: 0x10026568>) is not a data.table

如果我在data.table之前解析它,一切正常:

### ok
foo1 <- function(u) {
  nu <- deparse(substitute(u))
  u <- data.table(u)
  warning(nu, " is not a data.table")
  u
}
## foo1(e)
##      x
##  1:  1
##  2:  2
##  3:  3
##  4:  4
##  5:  5
##  6:  6
##  7:  7
##  8:  8
##  9:  9
## 10: 10
## Warning message:
## In foo1(e) : e is not a data.table

如果e已经 data.table,那么顺便说一下也没有区别。 我故意找到它,当我分析一些代码时,deparse非常耗时,因为e非常大。

此处发生了什么以及如何处理data.framedata.table输入的此类功能?

nachti

2 个答案:

答案 0 :(得分:14)

这是因为substitute在处理普通变量而不是promise对象时表现不同。 promise对象是一个形式参数,并且有一个特殊的插槽,其中包含生成它的表达式。换句话说,promise对象是函数中的变量,该函数是该函数的参数列表的一部分。在函数中的promise对象上使用substitute时,它将在调用分配给该形式参数的函数时检索表达式。来自?substitute

  

通过检查解析树的每个组件进行替换,如下所示:如果它不是env中的绑定符号,则不变。如果它是一个promise对象,即函数的形式参数或使用delayedAssign()显式创建, promise的表达式槽替换符号。如果它是普通变量,则其值被替换为,除非env是.GlobalEnv,在这种情况下符号保持不变。

在您的情况下,您实际上使用以下内容覆盖原始的promise变量:

u <- data.table(u)

此时u成为包含数据表的普通变量。在此substitute之后usubstitute只返回数据表,deparse处理回生成它的R语言,这就是为什么它慢。

这也解释了为什么你的第二个例子有效。你substitute变量仍然是一个承诺(即在你覆盖u之前)。这也是你第二个问题的答案。在您覆盖承诺之前要么替换,要么不要覆盖您的承诺。

有关详细信息,请参阅我在此处摘录的R语言定义(承诺)的 section 2.1.8

  

Promise对象是R懒惰评估机制的一部分。它们包含三个槽:值,表达式和环境。调用函数时,参数匹配,然后每个形式参数都绑定到一个promise。为该形式参数提供的表达式和调用该函数的环境的指针存储在promise中。

答案 1 :(得分:0)

您也可以使用sprintf以及is.data.table执行此操作。

> e <- data.frame(x = 1:10)
> foo <- function(u){
      nu <- deparse(substitute(u))
      if(!is.data.table(u)){
          warning(sprintf('%s is not a data table', nu))
          u
      } else {
          u
      }
  }
> foo(e)
    x
1   1
2   2
3   3
4   4
5   5
6   6
7   7
8   8
9   9
10 10
Warning message:
In foo(e) : e is not a data table