R data.table ':=' 在直接调用中工作,但包中的相同功能失败
R data.table ':=' works in direct call, but same function in a package fails
使用 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 指出在 package Depends
字段中添加 data.table 使其工作。但是,我认为这不是一个很好的解决方案,因为该包并不真正依赖、要求或使用 data.table。我只想能够将 data.table 与包一起使用。
此外,data.table 的其他所有内容在函数中都可以正常工作,只是 :=
运算符不行。
所以我想后续问题可能是:我是否应该将 data.table 添加到我编写的每个包的 Depends 中,以便 data.table 在该包的函数中按预期工作?这似乎不对...处理此问题的正确方法是什么?
我遇到了同样的问题,我通过将 data.table
添加到 Imports
和 Depends:
解决了这个问题。我的 data.table
版本是 1.9.6
我终于找到了这个问题的答案(几年后)。所有评论和答案都建议将data.table
添加到Depends
或Imports
,但这是不正确的;该包不依赖于 data.table
,并且假设它可以是任何包,而不仅仅是 data.table,这意味着逻辑结论,建议需要将所有可能的包添加到 Depends
--因为该依赖项是由提供 instruction
的用户提供的,而不是由包提供的功能提供的。
相反,基本上,这是因为对eval
的调用是在包的命名空间内完成的,这不包括其他包提供的功能。我最终通过在 eval
调用中指定全局环境解决了这个问题:
myFunc = function(instruction) {
eval(parse(text=instruction), envir=globalenv())
}
为什么这样有效
这会导致 eval
功能在搜索路径中包含必需包的环境中完成。
在 data.table
的情况下,由于函数重载的复杂性,调试起来特别困难。在这种情况下,罪魁祸首实际上不是 :=
函数,而是 [
函数。 :=
错误是转移注意力的错误。在撰写本文时,data.table
中的 :=
函数定义如下:
":=" <- 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
在参数评估阶段在包命名空间内被(错误地)解析,这样它就可以完整地回到 globalenv 中使用所需的功能正确评估。
使用 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 指出在 package Depends
字段中添加 data.table 使其工作。但是,我认为这不是一个很好的解决方案,因为该包并不真正依赖、要求或使用 data.table。我只想能够将 data.table 与包一起使用。
此外,data.table 的其他所有内容在函数中都可以正常工作,只是 :=
运算符不行。
所以我想后续问题可能是:我是否应该将 data.table 添加到我编写的每个包的 Depends 中,以便 data.table 在该包的函数中按预期工作?这似乎不对...处理此问题的正确方法是什么?
我遇到了同样的问题,我通过将 data.table
添加到 Imports
和 Depends:
解决了这个问题。我的 data.table
版本是 1.9.6
我终于找到了这个问题的答案(几年后)。所有评论和答案都建议将data.table
添加到Depends
或Imports
,但这是不正确的;该包不依赖于 data.table
,并且假设它可以是任何包,而不仅仅是 data.table,这意味着逻辑结论,建议需要将所有可能的包添加到 Depends
--因为该依赖项是由提供 instruction
的用户提供的,而不是由包提供的功能提供的。
相反,基本上,这是因为对eval
的调用是在包的命名空间内完成的,这不包括其他包提供的功能。我最终通过在 eval
调用中指定全局环境解决了这个问题:
myFunc = function(instruction) {
eval(parse(text=instruction), envir=globalenv())
}
为什么这样有效
这会导致 eval
功能在搜索路径中包含必需包的环境中完成。
在 data.table
的情况下,由于函数重载的复杂性,调试起来特别困难。在这种情况下,罪魁祸首实际上不是 :=
函数,而是 [
函数。 :=
错误是转移注意力的错误。在撰写本文时,data.table
中的 :=
函数定义如下:
":=" <- 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
在参数评估阶段在包命名空间内被(错误地)解析,这样它就可以完整地回到 globalenv 中使用所需的功能正确评估。