提问人:cdalitz 提问时间:11/14/2023 更新时间:11/16/2023 访问量:186
愚弄 R 的方法调度
Fooling R's Method Dispatch
问:
我正在寻找一个示例,其中函数名称中的点会导致 R 的方法调度选择错误的函数。一个自然的候选函数似乎是内置函数,当应用于类“test”的对象时,它应该被混淆。t.test()
t()
然而,奇怪的是,以下代码实际上调用了转置函数,而不是:t.test()
> x <- structure(cbind(1:4,2:5), class="test")
> class(x)
[1] "test"
> t(x)
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 2 3 4 5
这引发了两个问题:
- 为什么对象被转置而不是调用,因为它应该是由于方法调度的规则?
t.test()
- 通过定义一个内部带有点的函数来搞砸方法调度过程的(简单)示例是什么?
答:
3赞
MrFlick
11/14/2023
#1
您还必须考虑评估函数的环境。例如,如果你在环境中运行它,你会得到stats
t(x)
# [,1] [,2] [,3] [,4]
# [1,] 1 2 3 4
# [2,] 2 3 4 5
# attr(,"class")
# [1] "test"
evalq(t(x), envir=asNamespace("stats"))
# One Sample t-test
#
# data: x
# t = 6.4807, df = 7, p-value = 0.0003402
# alternative hypothesis: true mean is not equal to 0
# 95 percent confidence interval:
# 1.905392 4.094608
# sample estimates:
# mean of x
# 3
所以问题是该函数是在命名空间中定义的,而 在 .默认情况下,首先找到转置。t()
base
t.test()
stats
评论
0赞
cdalitz
11/15/2023
就像之前的搜索路径一样,我认为它应该有优先权。在 R 版本 3.5.1 中,它实际上具有,并且确实调用了 !它一定与在某个更高版本的 R 版本中引入的包中隐藏 S3 方法有关,因为在 R 4.2.1 中,这不再有效。请看@user2554330的答案。stats
base
t()
t.test()
3赞
user2554330
11/15/2023
#2
S3 调度很复杂。如果定义一个在全局环境中命名的函数,并使用 class 对对象调用该函数,则将调用该函数。但是,如果位于包中,则需要将其注册为 S3 方法才能以这种方式进行处理。(注册发生在文件中或通过执行 。t.test
t()
"test"
t.test()
t.test
NAMESPACE
registerS3method()
因此,这里有一个你正在寻找的示例:
t.test <- t.test
x <- 1
class(x) <- "test"
t(x)
#> Error in t.test.default(x): not enough 'x' observations
创建于 2023-11-14 with reprex v2.0.2
2018 年 R 3.5.0 发布时,有一些关于此的消息:第 8 个“新功能”在
https://developer.r-project.org/blosxom.cgi/R-3-5-branch/NEWS/2018/03/29#n2018-03-29
评论
0赞
cdalitz
11/15/2023
谢谢,这似乎是问题所在。刚刚在 R 3.51 中测试了它,那里不需要第一行:即使没有它,也被调用。因此,我猜想在包中隐藏 S3 函数是在后来的 R 版本中引入的。欢迎在发生这种情况时提供提示。t.test()
t()
评论
getS3method()
t.test
registerS3method('t', 'test', t.test)
t(x)
t.test()
stats
t.test
studentT
t.test
t
t()
t.test
t.test()
t()