【问题标题】:Why does the function t return a t.test for objects with class set to "test"?为什么函数 t 为类设置为“test”的对象返回 t.test?
【发布时间】:2016-03-12 20:43:43
【问题描述】:

我正在阅读 Hadley Wickham 的书 Advanced R,特别是 OO 领域指南 (http://adv-r.had.co.nz/OO-essentials.html)。该章的第一个练习如下:

阅读 t() 和 t.test() 的源代码并确认 t.test() 是 S3 泛型而不是 S3 方法。如果你创建一个带有类 test 的对象并用它调用 t() 会发生什么?

如果我对本章的理解正确,我们可以确认 t() 和 t.test() 是通用的,因为它们在源代码中使用了 UseMethod() 函数。 methods(t) 返回 t.data.frame、t.default 和 t.ts* 作为函数 t() 的方法。那么,如果两者都是 S3 泛型并且 t 没有 t.test 方法,那么为什么下面的代码会返回 t 测试?

a <- structure(1:4, class = "test")
t(a)

我的预测是 t 将使用类“test”的默认方法,并且 t.default(a) 会按照我认为的逻辑进行转置。那么 t.test 是从哪里来的呢?

【问题讨论】:

    标签: r


    【解决方案1】:

    如果您运行t(a),其中a 是您的类test 的对象,则调用UseMethod("t")。这将检查您提供给t() 的第一个参数的类是什么。班级是test,R 现在将 寻找函数t.test()。因为t.test() 存在,所以t.test(a) 运行。这称为“方法分派”。

    仅当t.test() 不存在时,R 才会求助于调用t.default()。实际上,您甚至可以通过在运行 t(a) 之前分离 stats 包来看到这种情况:

    a <- structure(1:4, class = "test")
    detach("package:stats")
    t(a)
    ##      [,1] [,2] [,3] [,4]
    ## [1,]    1    2    3    4
    ## attr(,"class")
    ## [1] "test"
    

    现在的问题是,当您运行methods("t") 时,为什么t.test 不包含在列表中。当你查看methods() 的源代码时,你会注意到它调用了.S3methods()。该函数编译t 的所有方法的名称。但是,在某些时候,它会删除 S3MethodsStopList 中包含的函数名称:

    info <- info[grep(name, row.names(info)), ]
    info <- info[!row.names(info) %in% S3MethodsStopList, 
        ]
    

    (如果我在 RStudio 中运行 edit(.S3methods),这些是第 47 和 48 行)。

    S3MethodsStopList 在前面定义(在第 15 行):

    S3MethodsStopList <- tools:::.make_S3_methods_stop_list(NULL)
    

    函数tools:::.make_S3_methods_stop_list() 似乎没有记录在案,但它似乎只是返回一个硬编码的函数名称列表,其中包含一个点,但实际上不是方法。 t.test() 就是其中之一:

    grep("^t\\.", tools:::.make_S3_methods_stop_list(NULL), value = TRUE)
    ##                 Hmisc6             calibrator                 mosaic               mratios1 
    ##       "t.test.cluster"                "t.fun"               "t.test"        "t.test.ration" 
    ##               mratios2               mratios3                 stats6 
    ## "t.test.ratio.default" "t.test.ratio.formula" 
    

    简而言之,methods() 会明确过滤掉已知不是方法的函数。另一方面,方法分派只是寻找具有适当名称的函数。

    【讨论】:

    • 知道了!感谢您的详尽解释!
    猜你喜欢
    • 2021-10-04
    • 1970-01-01
    • 2010-10-16
    • 2019-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-06
    • 2018-07-23
    相关资源
    最近更新 更多