【问题标题】:Reference Classes, tab completion and forced method definition参考类、制表符补全和强制方法定义
【发布时间】:2012-09-22 11:01:03
【问题描述】:

我目前正在使用引用类编写一个包。我遇到过 通过阅读各种来源的问题:

Method initialisation in R reference classes

Can't reliably use RefClass methods in Snowfall

我收集是因为引用方法没有全部复制到每个对象 在类中,而不是在第一次访问时复制它们。

https://stat.ethz.ch/pipermail/r-devel/2011-June/061261.html

例如定义:

test <- setRefClass("TEST",
                fields = list( a = "numeric"),
                methods = list(
                   addone = function(){
                                        a <<- a+1
                                      },
                   initialize = function(){
                                            a <<- 1
                                          }
                              )
               )

example <- test$new()

所以示例是类TEST 的新对象。键入 example$ 并在 控制台给出

> example$
# example$.->a         example$.refClassDef example$.self        
# example$a            example$initialize 

所以addone 方法没有作为选项提供。它可用于 但是调用:

example$addone()

现在标签再次显示

# > 
# > example
# Reference class object of class "TEST"
# Field "a":
# [1] 2
# > example$
# example$.->a         example$.refClassDef example$.self        
# example$a            example$addone       example$field        
# example$initialize   example$show

所以现在 addonefieldshow 作为选项提供。

Martin Morgan 建议在上述链接之一中强制定义方法。这 效果很好

test <- setRefClass("TEST",
                fields = list( a = "numeric"),
                methods = list(
                   addone = function(){
                                        a <<- a+1
                                      },
                   initialize = function(){
                                            a <<- 1
                                            .self$addone #force definition
                                          }
                              )
               )

example <- test$new()

所以现在制表符给出:

# > example$
# example$.->a         example$.refClassDef example$.self        
# example$a            example$addone       example$initialize  

我的一些类有超过 30 种方法,所以我想尽可能简洁地做到这一点。 我已经定义了:

test <- setRefClass("TEST",
                fields = list( a = "numeric"),
                methods = list(
                   addone = function(){
                                        a <<- a+1
                                      },
                   initialize = function(){
                      a <<- 1
                      eval(parse(text=paste0('.self$',ls(test$def@refMethods))))
                                          }
                              )
               )

example <- test$new()

tab 现在给出:

# > example$
# example$.->a         example$.refClassDef example$.self        
# example$a            example$addone       example$callSuper    
# example$copy         example$export       example$field        
# example$getClass     example$getRefClass  example$import       
# example$initFields   example$initialize   example$show         
# example$trace        example$untrace     

虽然这行得通,但感觉有点笨拙。还使用 test$def@refMethods 而不是 getRefClass("TEST")$def@refMethods 以便 感觉有点不对。以前有没有人处理过这个问题。

有没有更好的方法来解决问题?如果问题过于冗长,感谢您的任何建议和道歉。

【问题讨论】:

    标签: r s4 reference-class


    【解决方案1】:

    我想知道你的目标是什么?功能名称与选项卡完成一起显示?那么值得在 R-devel 邮件列表中发布一个功能请求。如?setRefClass 中所述,使用usingMethods 可以更优雅地处理原始场景。持续的黑客攻击可能是

    initialize = function(...) {
        methods <- getRefClass(class(.self))$methods()
        eval(parse(text=paste0(".self$", methods)))
        callSuper(...)
    }
    

    可以通过utils 包中的.DollarNames 自定义选项卡完成,所以

    .DollarNames.TEST <- function(x, pattern)
        grep(pattern, getRefClass(class(x))$methods(), value=TRUE)
    

    也许可以为此在类层次结构的基础上编写 S3 方法?

    【讨论】:

    • 谢谢你,这比我的解决方案更有帮助而且更优雅。另外我不知道它被称为标签完成。知道这个术语使我能够在 utils.xml 中找到相关的包。使用参考类完成制表符是我的目标,我将编辑问题标题以更好地反映这一点。
    • 这看起来很有希望。将.DollarNames.envRefClass &lt;- function(x, pattern) grep(pattern, getRefClass(class(x))$methods(), value=TRUE) 添加到我的包中会不会是个坏主意?
    • 是的,这是个坏主意——你会改变所有引用类的行为,而不仅仅是你自己的。也许有些人喜欢它当前的行为,也许methods 将在将来的某个日期实现一个超级骗子.DollarNames.envRefClass,然后你长期被遗忘的方法将覆盖它。正确的做法是在 R-devel 上将此作为功能请求提出,尤其是现在您至少有一个工作原型来说明您认为合适的行为。
    • 马丁摩根感谢您的时间和专业知识。我将向 R-devel 发布功能请求。
    【解决方案2】:

    我知道这是一个老问题,但它仍然是在谷歌上搜索 refClass 选项卡完成时的顶部条目,所以我将添加一个更新:

    不要像 Martin 建议的那样在 .DollarNames 函数中使用 grep,而是使用 utils 包中的 findMatches,因为它可以更好地与不同的 Rgui 配合使用(grep 会在点击选项卡时删除您部分输入的名称)

    .DollarNames.TEST <- function(x, pattern){
        utils:::findMatches(pattern, getRefClass(class(x))$methods())
    }
    

    这也是列表和 data.frames 内部处理选项卡完成的方式

    【讨论】:

      【解决方案3】:

      @Martin Morgan 指出这被称为制表符补全。包rcompletion 和后来的rcompgen 的任务是实现这一点。他们现已移至utils

      rcompletion update

      我查看了completion.R 的代码,据我所知,utils:::.DollarNames.environment 正在处理参考类的制表符补全。

      completion.R

      重新定义函数好像实现了tab补全:

      assignInNamespace( x = ".DollarNames.environment",
                           function(x, pattern = "") {
          y <- NULL
          if(isS4(x) && !is.null(x[['.refClassDef']])){
            if(.hasSlot(x$.refClassDef,'refMethods')){
              y<-x$.refClassDef@refMethods
              y<-ls(y, all.names = TRUE, pattern = pattern)
            }
          }
          x<-ls(x, all.names = TRUE, pattern = pattern)
          unique(c(x,y))
                                                     }
      ,ns = "utils")
      

      注意事项:

      • 我只会将其用于我自己的用途。目前我正在调试和记录一个包。我有一些冗长的方法名称,但不记得它们到底是什么,所以制表符补全会有很大帮助。

      • 不赞成在包中使用assignInNamespace(如果未禁止)请参阅?assignInNamespace

      • 强制定义方法更为可取。

      【讨论】:

      • 其实.DollarNames是一个S3泛型,所以你可以在上面写S3方法;我在回答中说明了这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-16
      相关资源
      最近更新 更多