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



使用 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 添加到我编写的每个包的依赖项中,以便 data.tables 在该包的函数中按预期工作?这似乎不对...解决这个问题的正确方法是什么?

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

我终于找到了这个问题的答案(几年后)。所有评论和答案都建议在DependsImports中添加data.table,但这是不正确的;包不依赖于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[函数。它尝试将:=评估为函数,[不会使用它,因为它不是正确的[,因此:=作为函数而不是作为值传递给data.table的,因为data.table不在命名空间中(或在search()层次结构中较低。在此设置中,:=不被理解,因此将其作为函数进行评估,从而触发上述data.table代码中的错误消息。

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

顺便说一下,如果你传递的不是字符串,而是代码块(更好)来eval()包中,你也可以使用它:

eval(substitute(instruction), envir=globalenv())

在这里,substitute 防止instruction在 argument-eval 阶段在包命名空间中被解析(错误),以便它完整地返回到 globalenv,在那里可以使用所需的函数正确评估它。

相关内容

  • 没有找到相关文章

最新更新