R 中的继承 [英] Inheritance in R

查看:20
本文介绍了R 中的继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于R,有人可以向我解释,关于对象继承,如果我有S4对象X,其中包含Y,如果Y有一个初始化程序,如何从X的初始化程序中调用该初始化程序,当 X 被构造时.

With regards to R, Can someone explain to me, with regards to object inheritance, if I have S4 object X, which contains Y, if Y has an initializer, how can that initializer be called from within the initializer of X, when X is constructed.

推荐答案

第一关,不够好

这里有两个类

.A <- setClass("A", representation(a="integer"))
.B <- setClass("B", contains="A", representation(b="integer"))

符号 .A 是一个类生成器函数(本质上是对 new() 的调用),并且是方法包中相对较新的添加.

The symbol .A is a class generator function (essentially a call to new()), and is a relatively new addition to the methods package.

这里我们写了一个initialize,A-method,使用callNextMethod来调用类的下一个方法(默认构造函数,initialize,ANY-method)

Here we write an initialize,A-method, using callNextMethod to call the next method (the default constructor, initialize,ANY-method) for the class

setMethod("initialize", "A", function(.Object, ..., a=integer()) {
    ## do work of initialization
    cat("A
")
    callNextMethod(.Object, ..., a=a)
})

a=a 对应的参数在... 之后,这样函数就不会将任何未命名的参数分配给a;这很重要,因为未命名参数应该(来自 ?initialize)用于初始化基类,而不是插槽;这一点的重要性在下文中变得显而易见.类似的B":

The argument corresponding to the slot a=a comes after ... so that the function does not assign any unnamed arguments to a; this is important because unnamed arguments are supposed (from ?initialize) to be used to initialize base classes, not slots; the importance of this becomes apparent below. Similarly for "B":

setMethod("initialize", "B", function(.Object, ..., b=integer()) {
    cat("B
")
    callNextMethod(.Object, ..., b=b)
})

并在行动

> b <- .B(a=1:5, b=5:1)
B
A
> b
An object of class "B"
Slot "b":
[1] 5 4 3 2 1

Slot "a":
[1] 1 2 3 4 5

其实这并不完全正确,因为默认的initialize是一个拷贝构造函数

Actually, this is not quite correct, because the default initialize is a copy constructor

.C <- setClass("C", representation(c1="numeric", c2="numeric"))
c <- .C(c1=1:5, c2=5:1)

> initialize(c, c1=5:1)
An object of class "C"
Slot "c1":
[1] 5 4 3 2 1

Slot "c2":
[1] 5 4 3 2 1

而我们的 initialize 方法已经破坏了契约的这一方面

and our initialize method has broken this aspect of the contract

>  initialize(b, a=1:5)   # BAD: no copy construction
B
A
An object of class "B"
Slot "b":
integer(0)

Slot "a":
[1] 1 2 3 4 5

事实证明复制构造非常方便,所以我们不想破坏它.

Copy construction turns out to be quite handy, so we don't want to break it.

有两种解决方案用于保留复制构造功能.第一个避免定义初始化方法,而是创建一个普通的旧函数作为构造函数

There are two solutions employed to retain copy construction functionality. The first avoids defining an initialize method, but instead creates a plain old function as a constructor

.A1 <- setClass("A1", representation(a="integer"))
.B1 <- setClass("B1", contains="A1", representation(b="integer"))

A1 <- function(a = integer(), ...) {
    .A1(a=a, ...)
}

B1  <- function(a=integer(), b=integer(), ...) {
    .B1(A1(a), b=b, ...)
}

这些函数包括 ... 作为参数,因此可以扩展类B1"并仍然使用其构造函数.这实际上很有吸引力;构造函数可以有一个带有文档参数的合理签名.initialize 可以用作复制构造函数(记住,没有 initialize,A1-method 或 initialize,B1-method,所以调用 .A1() 调用默认,复制构造函数能够初始化方法).函数 (.B1(A1(a), b=b, ...) 表示调用 B1 类的生成器,使用未命名的参数使用A1"构造函数创建其超类,并且对应于槽 b" 的命名参数.如上所述,从 ?initialize 开始,未命名参数用于初始化超类(当类结构涉及多重继承时,使用多个类). 构造函数的使用意味着类A1和B1可以不知道彼此的结构和实现.

These functions include ... as arguments, so that class "B1" can be extended and its constructor still used. This is actually quite attractive; the constructor can have a sensible signature with documented arguments. initialize can be used as a copy constructor (remember, there is no initialize,A1-method or initialize,B1-method, so the call .A1() invokes the default, copy-constructor able initialize method). The function (.B1(A1(a), b=b, ...) says "call the generator for class B1, with an unnamed argument creating its superclass using the "A1" constructor, and a named argument corresponding to slot b". As mentioned above, from ?initialize, the unnamed argument(s) are used to initialize superclass(es) (with plural classes when the class structure involves multiple inheritance). The use of constructors means that class A1 and B1 can be ignorant of each other's structure and implementation.

第二种解决方案,不太常用,它的全部功能是编写一个保留复制构造的初始化方法,沿着

The second solution, less commonly used in its full glory, is to write an initialize method that retains copy construction, along the lines of

.A2 <- setClass("A2", representation(a1="integer", a2="integer"),
     prototype=prototype(a1=1:5, a2=5:1))

setMethod("initialize", "A2", 
    function(.Object, ..., a1=.Object@a1, a2=.Object@a2)
{
    callNextMethod(.Object, ..., a1=a1, a2=a2)
})

参数 a1=.Object@a1 使用 .Objecta1 槽的当前值作为默认值,当方法被用作复制构造函数.该示例说明了使用 prototype 来提供不同于 0 长度向量的初始值.在行动:

The argument a1=.Object@a1 uses the current value of the a1 slot of .Object as a default, relevant when the method is being used as a copy constructor. The example illustrates the use of a prototype to provide an initial values different from 0-length vectors. In action:

> a <- .A2(a2=1:3)
> a
An object of class "A1"
Slot "a1":
[1] 1 2 3 4 5

Slot "a2":
[1] 1 2 3

> initialize(a, a1=-(1:3))    # GOOD: copy constructor
An object of class "A1"
Slot "a1":
[1] -1 -2 -3

Slot "a2":
[1] 1 2 3

不幸的是这种方法失败时尝试从基类初始化派生类.

Unfortunately this approach fails when trying to initialize a derived class from a base class.

最后一点是初始化方法本身的结构.上图是图案

One final point is the structure of the initialize method itself. Illustrated above is the pattern

## do class initialization steps, then...
callNextMethod(<...>)

so callNextMethod() 位于初始化方法的末尾.另一种选择是

so callNextMethod() is at the end of the initialize method. An alternative is

.Object <- callNextMethod(<...>)
## do class initialization steps by modifying .Object, e.g.,...
.Object@a <- <...>
.Object

更喜欢第一种方法的原因是涉及的复制较少;默认的 initialize,ANY 方法以最少的复制填充槽,而槽更新方法在每次修改槽时复制整个对象;如果对象包含大向量,这可能会非常糟糕.

The reason to prefer the first approach is that there is less copying involved; the default initialize,ANY-method populates slots with a minimum of copying, whereas the slot update approach copies the entire object each time a slot is modified; this can be very bad if the object contains large vectors.

这篇关于R 中的继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆