R data.table':='在直接调用中工作,但包中的相同功能失败

时间:2015-01-16 09:30:35

标签: r data.table colon-equals

使用R的data.table包,

这有效:

instruction = "a = data.table(name=1:3, value=1:3, blah=1:3); a[,c('value', 'blah'):=NULL]"
eval(parse(text=instruction))
#   name
#1:    1
#2:    2
#3:    3

这有效:

myFunc = function(instruction) {
eval(parse(text=instruction))
}
myFunc(instruction)
#   name
#1:    1
#2:    2
#3:    3

现在,将此函数放入包中,加载它,然后尝试调用它。这不起作用:

myFuncInPackage(instruction)
#Error in `:=`(c("value", "blah"), NULL) : 
#  Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":=").

为什么?


编辑:@Roland指出在包Depends字段中添加data.table使其有效。但是,我不认为这是一个很好的解决方案,因为该软件包并不真正依赖,要求或使用data.table。我只是希望能够在包中使用data.table。

此外,data.table的所有其他功能在函数中运行良好,而不是:=运算符。

所以我想一个后续问题可能是:我应该将data.table添加到我编写的每个包的Depends中,以便data.tables在该包的函数中按预期工作吗?这似乎不正确......解决这个问题的正确方法是什么?

2 个答案:

答案 0 :(得分:5)

我遇到了同样的问题,我解决了将data.table添加到ImportsDepends:的问题。我的data.table版本为1.9.6

答案 1 :(得分:1)

我终于找到了这个问题的答案(几年后)。所有评论和回答建议将data.table添加到DependsImports,但这是不正确的;该包不依赖于data.table,并且可能是假设的任何包,而不仅仅是data.table,意味着得出逻辑结论,该建议需要将所有可能的包添加到Depends - 因为依赖性由提供instruction的用户提供,而不是由包提供的功能提供。

相反,基本上,它是因为对eval的调用是在包的命名空间内完成的,并且这不包括其他包提供的功能。我最终通过在eval调用中指定全局环境来解决这个问题:

myFunc = function(instruction) {
eval(parse(text=instruction), envir=globalenv())
}

为什么会这样?

这会导致eval函数在包含搜索路径中必需包的环境中完成。

data.table情况下,由于函数重载的复杂性,它特别难以调试。在这种情况下,罪魁祸首实际上不是:=函数,而是[函数。 :=错误是一个红色的鲱鱼。在撰写本文时,:=中的data.table函数定义如下:

https://github.com/Rdatatable/data.table/blob/348c0c7fdb4987aa6da99fc989431d8837877ce4/R/data.table.R#L2561

":=" <- function(...) stop('Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":=").')

那就是它。这意味着:任何对:=作为函数的调用都会因错误消息而停止,因为这不是作者打算使用:=的方式。相反,:=实际上只是由[data.table函数解释的关键字。

但是这里会发生什么:如果[函数没有正确映射到data.table指定的版本,而是映射到基础[,那么我们有一个问题 - 因为它无法处理:=,因此它被视为一个函数并触发错误消息。因此,罪魁祸首函数是[.data.table - 重载的括号运算符。

我的新软件包中发生了什么(包含myFuncInPackage),在评估代码时,它将[函数解析为基础[函数而不是data.table的{​​{1}}功能。它会尝试将[评估为:=未使用的函数,因为它不是正确的[,因此[将被传递为函数而不是:=的值,因为data.table不在命名空间中(或在data.table层次结构中较低。在此设置中,{{1不被理解,因此它被评估为一个函数,从而在上面的search()代码中触发错误消息。

当您指定在全局环境中发生的eval时,它会正确地将:=函数解析为data.table,并正确解释[

顺便提一下,如果您在包中传递的不是字符串,而是代码块(更好)传递给[.data.table,也可以使用此功能:

:=

这里,eval()阻止eval(substitute(instruction), envir=globalenv()) 在参数-eval阶段的包命名空间内被解析(错误),这样它就可以完整地回到globalenv,在那里可以正确地评估substitute具备所需的功能。