12

使用 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 在该包的函数中按预期工作?这似乎不对......解决这个问题的正确方法是什么?

4

2 回答 2

7

我有同样的问题,我解决了它添加data.tableImportsand Depends:。我的data.table版本是1.9.6

于 2016-02-17T15:47:43.250 回答
6

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

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

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

为什么这有效

这会导致该eval功能在搜索路径中包含必要包的环境中完成。

在这种data.table情况下,由于函数重载的复杂性,调试起来特别困难。在这种情况下,罪魁祸首实际上不是:=函数,而是[函数。:=错误是一个红鲱鱼。在撰写本文时,:=函数 indata.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,而是映射到 base [,那么我们就有问题了——因为它无法处理:=,所以它被视为一个函数并触发错误信息。所以罪魁祸首是[.data.table——重载的括号运算符。

发生的事情是在我的新包(包含myFuncInPackage)中,当它去评估代码时,它将[函数解析为基本[函数而不是data.table函数[。它试图:=作为一个函数来评估,[因为它不是正确的[,所以它没有被使用,所以:=作为一个函数而不是作为一个值传递给data.table's,因为data.table它不在命名空间中(或者在search()层次结构中较低) . 在此设置中,:=无法理解,因此将其作为函数进行评估,从而触发上述data.table代码中的错误消息。

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

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

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

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

于 2017-08-14T21:22:08.927 回答