3

如何更新 R6 类实例的方法定义?

正如我所料,S3 使用当前的方法定义。使用 R5(参考类),我可以使用 myInstance=myInstance$copy()。使用 R6,我尝试了 myInstance = myInstance$clone() 但 myInstance$someMethod() 仍然调用旧代码。

当我从在长时间运行的进程上创建的转储中加载对象实例时,我需要这个。我想在长时间运行的计算后调试和更改对象状态的代码。因此,我不能只创建一个新实例并重新运行初始化。甚至比 R5 复制方法(不更新对实例的引用)更好的方法是将类和所有超类的当前定义的行为(即方法定义)分配给实例。

这是一个例子:

library(R6)

Person <- R6Class("Person",
        lock_objects=FALSE,
        public = list(
                name = NULL,
                initialize = function(name = NA, hair = NA) {
                    self$name <- name
                    self$greet()
                },
                greet = function() {
                    cat(paste0("Hello, my name is ", self$name, ".\n"))
                }
        )
)

# create an instance
thomas <- Person$new("Thomas","brown")

# modify the behaviour of Person
Person <- R6Class("Person",
        lock_objects=FALSE,
        public = list(
                name = NULL,
                initialize = function(name = NA, hair = NA) {
                    self$name <- name
                    self$greet()
                },
                greet = function() {
                    cat(paste0("Modified greet from ", self$name, ".\n"))
                }
        )
)

t1 <- Person$new("t1")  # greet function updated
t2 <- thomas$clone() 
t2$greet()              # greet function not updated in thomas nor t2
4

2 回答 2

1

这个问题有一个简单的解决方法。将类方法的默认值设置为NULL并在方法内更新此值initialize()。现在,您可以根据需要更改方法而不会收到此错误。例如:

aClass <- R6::R6Class("className",
  public = list(
    f = NULL,
    initialize = function(...) {
      self$f = sum
    },
    update_f = function(x) {
      self$f = x
    }
  )
)

test <- aClass$new()
test$f
test$update_f(mean)
test$f

或者,可以就地修改函数:

test$f <- median
test$f

那应该可以解决问题。我也在这里发布了这个答案。

于 2018-08-06T19:54:22.927 回答
0

我想出了以下技巧。继续问题中的代码,我设法更改了greetR6 对象实例中的方法定义thomas

replacePublicR6Method <- function( r6Instance, fName, fun){
    selfEnv <- environment(r6Instance[[fName]])$self
    properEnv <- environment( r6Instance[[fName]] )
    unlockBinding(fName, selfEnv)
    selfEnv[[fName]] <- fun
    environment(selfEnv[[fName]]) <- properEnv
    lockBinding(fName, selfEnv)
}

replacePublicR6Method( thomas, "greet", function(){
            cat(paste0("Modified greetings from ", self$name, ".\n"))
        })

thomas$greet() 

我猜绑定是故意锁定的,而且这个 hack 很脏。向 R-wizards 提出的问题:这个 hack 能否破坏 R6 类的其他一些行为?它会继续与 R6 类的未来版本一起使用吗?

为了在长时间运行的计算之后在对象状态下尝试一些代码修改,这应该没问题。到目前为止,它也适用于子类的实例。

于 2016-11-02T12:21:38.523 回答