【问题标题】:The inner workings of `NextMethod()``NextMethod()` 的内部工作原理
【发布时间】:2014-01-22 19:48:32
【问题描述】:

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

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

存在这个相当微妙的定义是为了确保 S 中的函数调用尽可能干净地传递给 方法(比较 Becker、Chambers 和 Wilks 的新 S 语言, 第 354 页)。特别是:

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

继承过程基本上是透明的 论据去。

我感到困惑的两点是:

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

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

【问题讨论】:

    标签: r oop inheritance methods parametric-polymorphism


    【解决方案1】:

    很难看完所有这篇文章,但我认为这个小例子可以帮助揭开NextMethod 调度的神秘面纱。

    我创建了一个具有 2 个类属性(继承)“第一”和“第二”的对象。

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

    然后我创建一个generic 方法Cat 来打印我的对象

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

    我为每个类定义了Cate 方法。

    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))
    }
    

    现在您可以使用此示例检查Cate 呼叫:

     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"
    
    • 对于 Cate.second,之前的方法是 Cate.first
    • 参数 x 和 y 从当前方法传递到继承的 方法及其在调用 NextMethod() 时的当前值。
    • 通过“...”形式参数传递的参数 y 以正确的参数名称到达 Cate.second(x = x, y = 1:3)

    【讨论】:

      【解决方案2】:

      考虑这个例子,其中泛型函数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.ordered 调用 f.factor 所以方法“调用为 调用 NextMethod 的结果是 f.factor ,前一个方法是 f.ordered.

      对继承方法的调用中的参数在 数字、顺序和实际参数名称与调用 当前方法(因此,在对泛型的调用中)。这 然而,参数的表达式是 当前方法的相应形式参数。假设,对于 例如,表达式 print(ratings) 调用了该方法 打印.ordered()。当此方法调用 NextMethod() 时,这是 相当于以 print.factor(x) 形式调用 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

      【讨论】:

        猜你喜欢
        • 2011-08-29
        • 2015-08-21
        • 1970-01-01
        • 2018-07-28
        • 2019-06-29
        • 2022-05-21
        • 2019-12-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多