【问题标题】:How do I call a namespaced function without evaluating the parameters you are giving it?如何在不评估您提供的参数的情况下调用命名空间函数?
【发布时间】:2011-11-30 21:33:57
【问题描述】:

在 R 中,在不评估您给它的参数的情况下调用另一个函数的惯用方式显然如下:

Call <- match.call(expand.dots = TRUE)
# Modify parameters here as needed and set unneeded ones to NULL.
Call[[1L]] <- as.name("name.of.function.to.be.called.here")
eval.parent(Call)

但是,当我在 as.name() 调用中输入命名空间名称(例如 utils::write.csv)时,出现错误:

"找不到函数 "utils::write.csv"

使用这个 R 成语调用命名空间函数的正确方法是什么?

【问题讨论】:

  • 在 R 中,在不计算参数的情况下调用函数的惯用方式是 f(x, y, z)。这就是惰性求值的意义所在!

标签: r


【解决方案1】:

这是一个使用do.call() 的解决方案,它既构造又评估函数调用。

与您开始使用的方法一样,此方法使用 R 调用是列表的事实,其中: (a) 第一个元素是函数的名称;并且 (b) 所有以下元素都是该函数的参数。

j <- function(x, file) {
    Call <- match.call(expand.dots = TRUE)
    arglist <- as.list(Call)[-1]
    do.call(utils::write.csv, arglist)
}

dat <- data.frame(x=1:10, y=rnorm(10))

j(dat, file="outfilename.csv")

编辑: FWIW,这里有一个来自plot.formula in base R 的示例,它使用与上述类似的构造:

{
    m <- match.call(expand.dots = FALSE)
    eframe <- parent.frame()
    . . .
    . . . 
    m <- as.list(m)
    m[[1L]] <- stats::model.frame.default
    m <- as.call(c(m, list(na.action = NULL)))
    mf <- eval(m, eframe)
    . . .
    . . . 
}

该函数稍后使用do.call() 构造。深入了解杂草,我的阅读是在这里显示的 sn-p 中,它使用了几个步骤,主要是因为需要将 na.action=NULL 添加到参数列表中。

无论如何,看起来do.call() 选项尽可能接近规范。

【讨论】:

  • 这对我来说失败了(R 2.14.0):找不到函数“utils::write.csv”
  • @Tommy -- 感谢您的关注。我最初将它用作名称(即不带引号),然后出于某种莫名其妙的原因对其进行了编辑。以为我已经检查过它是否可以双向工作,但我想不是。不过现在已修复。
  • @Tommy -- 另外,我添加了一个来自 base R 的示例,它使用 +/- 与我们两个答案中相同的方法。
  • 这对我有用。谢谢! do.call() 版本似乎也比 eval.parent() 版本更清晰。
  • 但是 write.csv(x, file) 没有这样做的原因是什么?
【解决方案2】:

正如@Josh O'Brien 回答的那样,do.call 使用起来更加直接。

do.call 的第一个参数可以是函数名或实际函数。 函数名可以包含命名空间限定符。 ::部分其实是一个函数,取两边的名字,找到对应的函数,所以必须单独求值才能工作。

因此,对于do.call,您需要类似:

# ...Stuff from Josh's answer goes here
# And then:
do.call(utils::write.csv, arglist)

还有eval:

Call <- match.call(expand.dots = TRUE)
# Modify parameters here as needed and set unneeded ones to NULL.
Call[[1L]] <- utils::write.csv
eval.parent(Call)

请注意函数名称周围没有引号。计算结果为函数闭包。

从命名空间限定名称获取函数的另一种方法:

eval(parse(text="utils::write.csv"))

再次调用:: 函数以正确找到该函数。

另一种更手动的方法是提取命名空间名称和函数名称,然后自己进行查找:

x <- strsplit("utils::write.csv", "::")[[1]]
get(x[2], asNamespace(x[1]))

【讨论】:

    猜你喜欢
    • 2020-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    • 1970-01-01
    • 2010-11-26
    • 1970-01-01
    相关资源
    最近更新 更多