【问题标题】:R S4 class inherited methods do not get loaded on first call, but work on the secondR S4 类继承的方法不会在第一次调用时加载,但在第二次调用时工作
【发布时间】:2017-11-20 14:05:00
【问题描述】:

我想学习 R 中的 OO 编程,作为练习,我正在编写一小组函数和方法来读写 Fortran 名称列表。我完全是个菜鸟,所以请善待下面的例子(你可以复制粘贴)。

我有以下类定义:

setClass("NamelistValue")
setClassUnion("NamelistValue", c("numeric", "character"))
setClass("Namelist",
        representation(group = "character", variable = "character", value = "NamelistValue", comment = "character", file="character"),
        prototype(group = NA_character_, variable = NA_character_, value = NA_real_, comment = NA_character_, file = NA_character_)
        )

例如这些替换数据的方法:

setMethod("[<-", c("Namelist", "character", "character", "NamelistValue"),
    function (x, i, j, ..., value) {
        if (length(i) > 1 | length(j) > 1) stop("Cannot subset with more than one index")
        l <- which(x@group==i)
        v <- which(x@variable[l]==j)
        vals <- x@value
        vals[l][v] <- value
        initialize(x, group=x@group, variable=x@variable, value=vals, comment=x@comment, file="<None>")
    }
)

setMethod("[<-", c("Namelist", "missing", "character", "NamelistValue"),
    function (x, i=NULL, j, ..., value) {
        if (length(i) > 1 || length(j) > 1) stop("Cannot subset with more than one index")
        v <- which(x@variable==j)
        vals <- x@value
        vals[v] <- value
        initialize(x, group=x@group, variable=x@variable, value=vals, comment=x@comment, file="<None>")
    }
)

现在我设置一个对象:

a <- new("Namelist", group="pippo", variable="ears", value=2, comment="Hi!")

让我们看看showMethods(class = "Namelist") 的方法,输出如下:

Function: [<- (package base)
x="Namelist", i="character", j="character", value="NamelistValue"
x="Namelist", i="missing", j="character", value="NamelistValue"

Function: initialize (package methods)
.Object="Namelist"
    (inherited from: .Object="ANY")

看起来不错。现在我尝试用a[,"ears"] &lt;- 4 替换一些值,命令失败

Error in `[<-`(`*tmp*`, , "ears", value = 4) : 
  argument "i" is missing, with no default

但是,如果我再次尝试相同的命令成功...我从showMethods(class = "Namelist") 看到已经创建/继承了一些额外的方法:

Function: [<- (package base)
x="Namelist", i="character", j="character", value="NamelistValue"
x="Namelist", i="missing", j="character", value="NamelistValue"
x="Namelist", i="missing", j="character", value="numeric"
    (inherited from: x="Namelist", i="missing", j="character", value="NamelistValue")

Function: initialize (package methods)
.Object="Namelist"
    (inherited from: .Object="ANY")

这是为什么?为什么它首先不起作用,而仅在第二次尝试中起作用?我该如何解决这个问题?

【问题讨论】:

  • 你有[[&lt;- 的方法吗?这可能与这些是内部泛型有关,但老实说我不太确定......
  • 问题中的示例是 MRE,因此在 R 会话中没有做任何其他事情。

标签: r methods s4


【解决方案1】:

(我没有 R 的源代码,很高兴有人编辑它。[&lt;- 是内部的,所以我只能看到它的文档的代码。)

内部泛型在分派方法之前会对其自身进行一些检查,这包括评估签名中的所有参数(包括i)。所以你的第一次调用失败了,因为i 没有默认值可以依赖(该方法尚未注册)。然而,默认方法已经足够注册一个 S4 方法存在,所以当调用退出时,该方法已经被注册。

这可以通过查看showMethods("[&lt;-") 在第一次通话之前和之后看到。之后,尽管出现错误,但它显示了继承的方法。

第二个调用有一个预先注册的方法,因为签名完全匹配所以直接调用它。这看到了i 的默认NULL 并根据需要使用它,而[&lt;- 的泛型从未被调用,因此我们不再看到错误。

我认为selectMethod 可能会以类似的方式注册这些方法而不会出错,但显然事实并非如此。可能的解决方法可能是:

  • NamelistValue 的每个子类编写单独的方法(糟糕!)
  • 使用显式的"" 而不是缺少的参数:a["","ears"] &lt;- ... --- 这不会导致错误,副作用最小并注册必要的方法。问题是你必须分别为字符和数字做:

    a["","耳朵"]

这应该涵盖所有继承的方法,尽管我很欣赏它并不理想...

【讨论】:

  • 我不确定我是否理解您的意思,您能举个例子吗?问题中的一个是 MRE,所以你可以复制粘贴它。
  • 做了一些编辑,希望能让事情更清楚,我自己做了一些实验......
  • 对不起,我帮不上忙;我希望会有一个像registerMethods 这样的函数来注册方法而不实际调用它们。内部泛型是有趣的野兽......
  • 我突然想到这可能与 [&lt;- 的参数匹配不遵循通常的规则有关,所以也许签名不能正常工作?跨度>
  • 不知道,有什么方法可以测试吗?我真的是 S3/4 编程的菜鸟。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-03
相关资源
最近更新 更多