更新R6对象实例中的方法定义

时间:2016-10-07 10:11:47

标签: r r6

如何更新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

2 个答案:

答案 0 :(得分:0)

我提出了以下黑客攻击。 继续问题中的代码,我设法更改了R6对象实例greetthomas的方法定义:

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() 

我猜绑定是故意锁定的,这个黑客很脏。 对R-Wizards的提问:这个hack能破坏R6类的其他一些行为吗?它会继续使用未来版本的R6类吗?

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

答案 1 :(得分:0)

此问题有一个简单的解决方法。将类方法的默认值设置为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

那应该可以解决问题。我还发布了此答案here