12

我试图弄清楚是如何NextMethod()工作的。我在 Chambers & Hastie (edts.)'s Statistical Models in S (1993, Chapman & Hall) 中找到了关于S3 类系统的最详细解释,但我发现关于NextMethod调用的部分有点晦涩难懂。以下是我试图理解的相关段落(第 268-269 页)。

现在转向作为调用的结果调用的方法 NextMethod(),这些方法的行为就好像它们是从以前的方法中通过特殊调用调用的一样。对继承方法的调用中的参数在数量、顺序和实际参数名称上与对当前方法的调用中的参数名称相同(因此,在对泛型的调用中)。然而,参数的表达式是当前方法的相应形式参数的名称。例如,假设表达式print(ratings)调用了方法print.ordered()。当这个方法被调用 NextMethod()时,这相当于对print.factor()表单的调用print.factor(x),这里xx在框架中的 print.ordered()。如果多个参数与形式参数匹配“...”,这些参数在对继承方法的调用中表示 y 特殊名称“ ..1”、“ ..2”等。评估器识别这些名称并适当地对待它们(参见第 476 页的示例)。

存在这个相当微妙的定义是为了确保 S 中函数调用的语义尽可能干净地延续到方法的使用中(比较 Becker、Chambers 和 Wilks 的The New S Language,第 354 页)。尤其是:

  • 参数从当前方法传递到继承方法,并在NextMethod()调用时使用它们的当前值。
  • 惰性评估继续有效;未评估的论点保持未评估。
  • 继承的方法中仍然缺少缺少的参数。
  • 通过" " 形式参数传递的...参数以正确的参数名称到达。
  • 框架中与调用中的实际参数不对应的对象将不会传递给继承的方法。”

就参数而言,继承过程基本上是透明的。

我感到困惑的两点是:

  1. 什么是“当前方法”,什么是“以前的方法”?
  2. “对继承方法的调用中的参数”,“参数的表达式”和“当前方法的相应形式参数的名称”有什么区别?

一般来说,如果有人能以一种清晰的方式重述上述段落中的描述,我将不胜感激。

4

2 回答 2

11

Hard to go through all this post, but I think that this small example can help to demystify the NextMethod dispatching.

I create an object with 2 classes attributes (inheritance) 'first' and 'second'.

x <- 1
attr(x,'class') <- c('first','second')

Then I create a generic method Cat to print my object

Cate <- function(x,...)UseMethod('Cate')

I define Cate method for each class.

Cate.first <- function(x,...){
  print(match.call())
  print(paste('first:',x))
  print('---------------------')
  NextMethod()                ## This will call Cate.second
}

Cate.second <- function(x,y){
  print(match.call())
  print(paste('second:',x,y))
}

Now you can can check Cate call using this example:

 Cate(x,1:3)
Cate.first(x = x, 1:3)
[1] "first: 1"
[1] "---------------------"
Cate.second(x = x, y = 1:3)  
[1] "second: 1 1" "second: 1 2" "second: 1 3"
  • For Cate.second the previous method is Cate.first
  • Arguments x and y are passed down from the current method to the inherited method with their current values at the time NextMethod() is called.
  • Argument y passed through the "..." formal argument arrive with the correct argument name Cate.second(x = x, y = 1:3)
于 2014-01-05T11:53:33.197 回答
7

考虑这个例子,其中泛型函数f被调用并调用f.ordered,然后,使用NextMethodf.ordered调用f.factor

f <- function(x) UseMethod("f")  # generic
f.ordered <- function(x) { x <- x[-1]; NextMethod() }
f.factor <- function(x) x # inherited method
x <- ordered(c("a", "b", "c"))

class(x)
## [1] "ordered" "factor" 

f(x)
## [1] b c
## Levels: a < b < c

现在考虑原文:

现在转向作为调用 NextMethod() 的结果调用的方法,这些方法的行为就好像它们是通过特殊调用从前一个方法调用的一样。

这里f调用f.orderedwhich 调用f.factor,因此“作为调用 NextMethod 的结果而调用的方法”是f.factor,前一个方法是 f.ordered

对继承方法的调用中的参数在数量、顺序和实际参数名称上与对当前方法的调用中的参数名称相同(因此,在对泛型的调用中)。然而,参数的表达式是当前方法的相应形式参数的名称。例如,假设表达式 print(ratings) 调用了 print.ordered() 方法。当此方法调用 NextMethod() 时,这等效于调用 print.factor() 形式的 print.factor(),其中 x 在这里是 print.ordered() 框架中的 x

现在我们切换视角,我们坐在那里,f.ordered所以现在f.ordered 是当前方法,f.factor也是继承的方法。

f.ordered在调用NextMethod()特殊调用的那一点上,调用f.factor其参数与传递给f.ordered和传递给泛型的参数相同,f 只是它们引用了参数的版本f.ordered(这f.ordered在调用 f.factor.

于 2014-01-05T12:43:54.433 回答