R中的继承 [英] Inheritance in R

查看:222
本文介绍了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 first pass, not quite good enough

Here are two classes

.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.

这里我们用 callNextMethod <写一个初始化的A方法/ code>为类调用下一个方法(默认构造函数,初始化,ANY方法)

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\n")
    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\n")
    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

和我们的初始化方法违反了合同的这一方面

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 可以用作复制构造函数(记住,没有初始化,A1方法或初始化,B1方法,所以调用 .A1 ()调用默认的copy-constructor able initialize方法)。函数( .B1(A1(a),b = b,...)表示为类B1调用生成器,使用未命名的参数创建其超类A1构造函数和对应于槽b的命名参数。如上所述,从?initialize ,未命名的参数用于初始化超类(es) (当类结构涉及多重继承时,使用多个类。)构造函数的使用意味着类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 使用<的当前值code> a1 插槽 .Object 作为默认值,在将该方法用作复制构造函数时相关。该示例说明了使用 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.

最后一点是结构initialize方法本身。上面的插图是模式

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

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

所以 callNextMethod()是在initialize方法的最后。另一种选择是

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

更喜欢第一种方法的原因是涉及的复制较少;默认初始化,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天全站免登陆