3

我正在开发我的第一个包,它针对的是 R 新手,因此我试图尽量减少使用该包所需的 R 技能数量。因此,我想要一个函数来更改我包中其他函数的默认值。但是我收到以下错误“无法将绑定添加到锁定的环境”,这意味着包的环境被锁定,我不允许更改其函数的默认值。

这是一个引发类似错误的示例:

library(ggplot2)
assign(formals(geom_point)$position, "somethingelse", pos="package:ggplot2")

当我尝试 assignInNamespace 时,我得到: bindingIsLocked(x, ns) 中的错误:“身份”没有绑定

assignInNamespace(formals(geom_point)$position,"somethingelse", pos = "package:ggplot2")

这是我希望实现的一个例子。

default <- function(x=c("A", "B", "C")){
       x
       }
default()

change.default <- function(x){
formals(default)$x <<- x        # Notice the global assign
}

change.default(1:3)
default()

我知道这远非推荐的方法,但我愿意偷工减料以改善包的学习曲线。有没有办法做到这一点?

此问题已被标记为Setting Function Defaults R on a Project Specific Basis的副本。这是一种不同的情况,因为这个问题涉及如何允许用户在交互式会话中更改函数的默认值 - 而不是如何实际执行。使用 options() 函数无法解决旧问题,因此这是一个不同的问题。

4

2 回答 2

4

我认为实现您想要的通俗方式是 viaoption和包实际上是这样做的,例如lattice(尽管它们使用特殊选项)或ascii.

此外,这在基础 R 中也是如此,例如著名且臭名昭著的stringsAsFactors.

如果你看?read.table?data.frame你得到:stringsAsFactors = default.stringsAsFactors()。检查显示:

> default.stringsAsFactors
function () 
{
    val <- getOption("stringsAsFactors")
    if (is.null(val)) 
        val <- TRUE
    if (!is.logical(val) || is.na(val) || length(val) != 1L) 
        stop("options(\"stringsAsFactors\") not set to TRUE or FALSE")
    val
}
<bytecode: 0x000000000b068478>
<environment: namespace:base>

这里的相关部分是getOption("stringsAsFactors")产生:

> getOption("stringsAsFactors")
[1] TRUE

改变它是这样实现的:

> options(stringsAsFactors = FALSE)
> getOption("stringsAsFactors")
[1] FALSE

要执行您想要的操作,您的包需要设置一个选项,并且该函数将其值从选项中获取。然后另一个函数可以更改选项:

options(foo=c("A", "B", "C"))

default <- function(x=getOption("foo")){
    x
}
default()

change.default <- function(x){
    options(foo=x)
}

change.default(1:3)
default()

如果你希望你的包在加载时设置选项,你.onAttach需要.onLoadzzz.R. 例如,我的afex包会执行此操作并更改默认对比度。在您的情况下,它可能如下所示:

.onAttach <- function(libname, pkgname) {
    options(foo=c("A", "B", "C"))
}

ascii通过.onLoad(我不记得确切的区别是什么,但编写 R 扩展会有所帮助)。

于 2013-03-17T13:59:44.123 回答
3

优选地,函数具有以下内容:

  1. 输入参数
  2. 用这些参数做某事的函数体
  3. 输出参数

因此,在您想要更改函数行为的情况下,以最佳方式更改输入参数。例如,请参阅我对另一篇文章的回答。

您还可以使用 anoption来保存一些全局设置(例如,要使用哪种字体,存储您使用的包的路径),请参阅上面链接的问题中@James 的答案。但是要谨慎使用这些东西,因为它会使代码难以阅读。我将主要使用它们只读,即设置一次(由包或用户)并且不允许函数更改它们。

不可读性源于这样一个事实,即函数的行为不仅由本地决定(即由直接使用它的代码),而且还由远处的设置决定。这使得仅通过查看调用它的代码很难确定函数的作用,但是您必须深入挖掘更多代码才能完全理解正在发生的事情。此外,如果其他函数改变了这些选项,这使得预测给定函数将做什么变得更加困难,因为它取决于函数的历史。我之前对只读选项的建议又回到了这里,如果这些是只读的,一些关于可读性的问题就会减少。

于 2013-03-17T13:41:32.820 回答