如果我想将函数的参数解析为错误或警告,如果参数转换为函数中的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.frame
和data.table
输入的此类功能?
nachti
答案 0 :(得分:14)
这是因为substitute
在处理普通变量而不是promise对象时表现不同。 promise对象是一个形式参数,并且有一个特殊的插槽,其中包含生成它的表达式。换句话说,promise对象是函数中的变量,该函数是该函数的参数列表的一部分。在函数中的promise对象上使用substitute
时,它将在调用分配给该形式参数的函数时检索表达式。来自?substitute
:
通过检查解析树的每个组件进行替换,如下所示:如果它不是env中的绑定符号,则不变。如果它是一个promise对象,即函数的形式参数或使用delayedAssign()显式创建, promise的表达式槽替换符号。如果它是普通变量,则其值被替换为,除非env是.GlobalEnv,在这种情况下符号保持不变。
在您的情况下,您实际上使用以下内容覆盖原始的promise变量:
u <- data.table(u)
此时u
成为包含数据表的普通变量。在此substitute
之后u
,substitute
只返回数据表,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