覆盖在命名空间中导入的函数
Posted
技术标签:
【中文标题】覆盖在命名空间中导入的函数【英文标题】:Override a function that is imported in a namespace 【发布时间】:2011-09-09 10:20:02 【问题描述】:由于 R 中的 termplot
函数包含一些奇怪的代码,这些代码会给我带来烦人的错误,我想在我自己的测试代码中覆盖它,直到找到更持久的解决方案。问题是 mgcv
包没有加载更改的函数。 mgcv
包使用 NAMESPACE 文件中的 importFrom()
从其命名空间中的 stats 包加载 termplot。
如何说服 mgcv 使用更改后的术语图?我试过了:
unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, as.environment("package:stats"))
lockBinding("termplot", as.environment("package:stats"))
当应用于 lm-objects 时,这有效并且使用了更改后的术语图。但是当使用由 mgcv 包制作的 gam-objects 时,这是行不通的。如果可以避免的话,我真的不会从源代码构建 stats 包...
为了澄清,我也尝试过
assignInNamespace("termplot", my.termplot, ns="stats")
assignInNamespace("termplot", my.termplot, ns="mgcv")
在所有可能的组合中,在附加 mgcv 之前,在附加 mgcv 之后,我没有设法让它工作。
编辑:
我尝试了这里给出的所有选项(除了重建任何一个包),但无法让它工作。对我来说最简单的方法是使用包装函数。可以在here 找到该讨论。感谢所有提示。
一个可重现的例子:
my.termplot <- function (x) print("my new termplot")
unlockBinding("termplot", as.environment("package:stats"))
assignInNamespace("termplot", my.termplot, ns="stats", envir=as.environment("package:stats"))
assign("termplot", my.termplot, as.environment("package:stats"))
lockBinding("termplot", as.environment("package:stats"))
y <- 1:10
x <- 1:10
xx <- lm(y~x)
termplot(xx)
require(mgcv)
dat <- gamSim(1, n = 400, dist = "normal", scale = 2)
b <- gam(y ~ s(x0) + s(x1) + s(x2) + x3, data = dat)
plot(b,all=TRUE)
plot.gam
为非平滑项(在本例中为 x3)调用 termplot,但找不到新的 termplot 函数。
EDIT2:显然,我的示例有效。我现在看到我解决了自己的问题:在第一个代码中,我没有在 assignInNamespace 中添加命名空间和包。重要的是要记住在加载另一个包之前更改命名空间和包中的函数。感谢@hadley 为我指明了正确的方向,@Marek 用于测试代码并报告它的工作原理,其余的则用于努力回答。
【问题讨论】:
您在加载统计信息之前尝试使用assignInNamespace
吗?例如。在.Rprofile中? ?assignInNamespace
中有注释:“assignInNamespace
更改命名空间中的副本,但没有任何已从命名空间导出的副本”
@Joris:请举例说明您如何调用termplot
。显而易见的答案是打电话给my.termplot
或你覆盖的stats::termplot
,但我想这对你来说是不可能的。
@Richie @Joris 并没有真正调用 termplot()
,mgcv 正在调用 termplot()
,而 Joris 想要一种方法让 mgcv 看到他分配给 stats 命名空间的新版本 termplot ,但无法让 mgcv 看到除原件之外的任何内容。
@Marek :会尝试。我确实检查过; termplot
和 stats:termplot
都返回正确的函数。这就是我使用整个 unlockBinding... 的原因。但不知何故,mgcv 在其他地方得到了它。谢谢你的小费
这将很难,因为您需要覆盖 S3 方法表中的函数。
【参考方案1】:
我很难过 - 我无法弄清楚 plot.gam
是如何定位 termplot
- 据我所知,它没有使用普通的范围规则。这似乎需要对命名空间的理解比我目前拥有的更深入。
my.termplot <- function (x) print("my new termplot")
# where is it defined?
getAnywhere("termplot")
# in package and in namespace
unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, "package:stats")
unlockBinding("termplot", getNamespace("stats"))
assign("termplot", my.termplot, getNamespace("stats"))
getAnywhere("termplot")[1]
getAnywhere("termplot")[2]
# now changed in both places
y <- 1:10
x <- 1:10 + runif(10)
xx <- lm(y ~ x)
termplot(xx) # works
library("mgcv")
b <- gam(y ~ s(x), data = data.frame(x, y))
plot(b) # still calls the old termplot
# I'm mystified - if try and find termplot as
# seen from the environment of plot.gam, it looks
# like what we want
get("termplot", environment(plot.gam))
【讨论】:
我在debug
模式下运行plot.gam
,它似乎从不调用termplot
。 termplot
取决于if (n.para > 0)
条件,在您的情况下为FALSE
。 termplot(b)
按预期工作。
但是在 Joris 数据上的工作就像一个魅力(即:返回关于未使用参数的错误)。
平滑器的绘图在函数 plot.gam() 中编码。仅当我是对的时才对非平滑项调用 Termplot,这就是我使用该示例的原因。您的代码确实有效。显然,我还需要在命名空间中解锁术语图。我猜...
哦,我以为我也尝试了原始示例,但都没有成功。
你怎么能阻止mgcv
这样加载? - - 我不明白termplot
是如何覆盖所有其他plot
函数的。如何使库及其功能持久化?【参考方案2】:
我认为 trace() 函数会自动执行上面尝试的操作。做:
trace('termplot', edit='gedit')
其中 'gedit' 是文本编辑器的名称。编辑器将打开原始代码,您可以粘贴您想要的任何替换代码。
要返回原始版本,只需 untrace('termplot')
警告:当文本编辑器打开许多文件但它不起作用时,我尝试使用它。所以我在我的系统上使用了一个我不经常使用的文本编辑器“gedit”。这样我确信 R 会打开一个新的 'gedit' 实例。
我不确定这会有所帮助,但我认为值得一试。有命名空间时的搜索顺序真的很混乱。
【讨论】:
感谢您的提示,但这无济于事。我确实在 stats 包中获得了已编辑的版本,但 mgcv 继续使用旧版本。【参考方案3】:尝试覆盖您从中调用termplot
的函数。猜测一下,这是mgcv
包中的plot.gam
。
首先加载必要的包。
library(mgcv)
这是您的备用 termplot
函数,已添加到 stats
命名空间。
my.termplot <- function (model, ...)
message("In my.termplot")
unlockBinding("termplot", as.environment("package:stats"))
assign("termplot", my.termplot, as.environment("package:stats"))
lockBinding("termplot", as.environment("package:stats"))
同样,这是添加到 mgcv
命名空间的包装函数。
my.plot.gam <- function (x, ...)
message("In my.plot.gam")
my.termplot()
unlockBinding("plot.gam", as.environment("package:mgcv"))
assign("plot.gam", my.plot.gam, as.environment("package:mgcv"))
lockBinding("plot.gam", as.environment("package:mgcv"))
这是一个测试它的例子,取自?gam
。
dat <- gamSim(1, n = 400, dist = "normal", scale = 2)
b <- gam(y ~ s(x0) + s(x1) + s(x2) + s(x3), data = dat)
plot(b)
【讨论】:
我必须同时覆盖 termplot 和 plot.gam,这会导致 mgcv 命名空间内出现新的冲突。试过了,我得到的只是更多的错误...... 使用示例代码,它可以工作。当我使用真实代码(即在 plot.gam 的情况下,正是 plot.gam 函数的代码)执行此操作时,我会从命名空间中的其他冲突中得到后续错误。不过感谢您的努力。以上是关于覆盖在命名空间中导入的函数的主要内容,如果未能解决你的问题,请参考以下文章