使用原始实现的覆盖方法来扩展它 [英] Overwrite method to extend it, using the original implementation

查看:84
本文介绍了使用原始实现的覆盖方法来扩展它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

无论是在包装中,还是偶尔在基数R中,我有时都想为现有功能添加些许风味.在大多数情况下,这只是在函数的开始或结尾处发生的细微变化(愚蠢的例子:我希望cat函数默认在结尾处包含换行符).

现在,我知道可以通过将新的实现分配给它的名称BUT来简单地覆盖现有方法:那么,如何仍然可以使用旧方法呢?对于cat,我将必须执行以下操作:

cat<-function(... , file = "", sep = " ", fill = FALSE, labels = NULL,
    append = FALSE)
{
  cat(..., "\n" , file = file, sep = sep, fill = fill, labels = labels,
    append = append)
}

这意味着在新版本的实现中使用旧" cat.现在,如果我了解有关R中的调用和后期绑定如何工作的任何信息,那么它将简单地失败(无限递归).

那么有一种方法可以实现这一目标(本着面向对象的功能重写的精神),而无需诉诸

  • 给我的新函数起另一个名字(我希望它正常工作")
  • 使用其他名称保存旧功能(然后,当我创建 在另一个R会话中使用此功能,我可能会忘记多余的步骤)
  • 使用原始函数的所有来源(正如@Andrie所说:拥有最优雅的解决方案很重要)

这是否有范例?还是我该如何以最安全的方式来解决这个问题?还是我只是希望太多?

编辑给出@Andrie的答案:这可以非常简单地完成.但是,如果我想更改由包中另一个函数调用的包中某个函数的行为,Andrie的把戏将不起作用.

作为一个例子:我对glmnet程序包的绘图功能做了许多补充.但是,如果您查看plot.cv.glmnet之类的内容,您会发现它们将调用转发到该程序包中的另一个函数,因此,我确实需要将我的新版本注入到程序包中(顺便说一句,可以用reassignInPackage完成).但是,然后命名空间前缀当然会失败,因为我刚刚替换了命名空间版本.这个例子并不像看起来那样人为:我去过那里很多次了.另一方面,也许有人会/可以说我应该在这种情况下放弃我的要求?那么哪种方法最好呢?

解决方案

如果我理解正确,我认为引用namespace::function很简单,即在这种情况下,在函数内使用base::cat.

例如:

cat <- function(... , file = "", sep = " ", fill = FALSE, labels = NULL,
    append = FALSE)
{
  base::cat(..., "\n" , file = file, sep = sep, fill = fill, labels = labels,
      append = append)
}

> cat("Hello", "world!")
Hello world! 
> cat("Text on line 2")
Text on line 2 

Whether in a package or occasionally in base R, I sometimes want to add a little flavor to an existing function. Most of the times, this is a minor change of what should happen at the start or at the end of the function (silly example: I'd like the cat function to include a newline at the end by default).

Now I know I can simply overwrite an existing method by assigning my new implementation to its name, BUT: how, then, can I still use the old one? In the case of cat, I would have to do something like:

cat<-function(... , file = "", sep = " ", fill = FALSE, labels = NULL,
    append = FALSE)
{
  cat(..., "\n" , file = file, sep = sep, fill = fill, labels = labels,
    append = append)
}

This means using the 'old' cat in the implementation of the new one. Now if I understand anything about how calling and late binding in R work, this will simply fail (infinite recursion).

So is there a way of achieving this (in the spirit of object-oriented overrides of functions), without resorting to

  • giving my new function another name (I want it to 'just work')
  • saving the old function under some other name (Then, when I create this function in another R session, I might forget the extra step)
  • using all the source of the original function (As @Andrie said: it is important to have the most elegant solution possible)

Is there a paradigm for this? Or how could I go about this in the safest way possible? Or am I just wishing for too much?

Edit Given @Andrie's answer: this can be done quite simply. However, Andrie's trick will not work if I want to alter the behaviour of some function in a package that is called by another function in the package.

As an example: I have made numerous additions to the plotting functions of the glmnet package. But if you look at plot.cv.glmnet and the likes, you will see that they forward the call to another function within that package, so I'd really need to inject my new version into the package (which, by the way, can be done with reassignInPackage). But then of course the namespace prefixing will fail because I've just replaced the namespaced version. This example is not as contrived as it might seem: I've been there quite a few times. On the other hand, maybe somebody will/can argue that I should drop my requirements in that case? Which would be the best way to go then?

解决方案

If I understand you correctly, I think it's a simple matter of referring to namespace::function, i.e. in this case use base::cat inside your function.

For example:

cat <- function(... , file = "", sep = " ", fill = FALSE, labels = NULL,
    append = FALSE)
{
  base::cat(..., "\n" , file = file, sep = sep, fill = fill, labels = labels,
      append = append)
}

> cat("Hello", "world!")
Hello world! 
> cat("Text on line 2")
Text on line 2 

这篇关于使用原始实现的覆盖方法来扩展它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆