<p>R6 等价于 python __call__ dunder 方法</p>

创建于 2020-11-29  ·  7评论  ·  资料来源: r-lib/R6

@wch

是否有任何R6相当于__call__ dunder方法python基本上使得类实例调用的功能等? 这是可以添加的可能功能吗? 会有人对这个功能感兴趣吗?

就像是:

foo <- R6::R6Class(
  "foo",
  public = list(
    .__call__ = function(args) {...}
  )
)

bar <- foo$new()
bar(...)

通过为现有泛型编写S3方法,几乎​​所有其他 dunder 方法都可以在R实现,但是这个似乎需要由R6内部处理,如果这是可能的。

所有7条评论

我很确定在 R 中,使用()仅当对象是函数时才有效。 您可以做的是返回该函数,并将 R6 对象作为属性添加到它。

library(R6)

Foo <- R6Class("Foo",
  public = list(
    call = function() {
      self$x
    },
    x = 10,
    printx = function() {
      cat("The value of x is", self$x)
    }
  )
)

foo <- function() {
  obj <- Foo$new()

  # Return the obj$call method, and attach the full object as an attribute named
  # 'impl'. Also add the class "wrapped" to it so that we can define `$` and 
  # `$<-` methods for it.
  structure(
    obj$call,
    impl = obj,
    class = "wrapped"
  )
}

# The $ and $<- methods essentially pass through to the "impl" object attached
# to the function.
`$.wrapped` <- function(x, name) {
  obj <- attr(x, "impl", exact = TRUE)
  obj[[name]]
}

`$<-.wrapped` <- function(x, name, value) {
  obj <- attr(x, "impl", exact = TRUE)
  obj[[name]] <- value
  x
}



f <- foo()
f()
#> [1] 10
f$printx()
#> The value of x is 10
f$x
#> [1] 10

f$x <- 20
f()
#> [1] 20
f$printx()
#> The value of x is 20

dunder 调用方法感觉非常不 - R -like,所以我有点认为这是不可能的。 不过,这是一个有趣的解决方法。 非常聪明。 感谢您的回复。

我想缺点是缺乏对内部函数( f$printx() )和内部参数f$printx(arg)的自动完成帮助,这似乎是不可避免的。

您可以添加自动完成功能:

.DollarNames.wrapped <- function(x, pattern) {
  ls(attr(x, "impl", exact = TRUE))
}

呃,哇。 太棒了。 很酷。

@wch

我还有一个奇怪的问题,你也许可以解决。 但是这个特别奇怪。

类似于上面关于拥有一个看起来和感觉起来像一个普通对象的对象的问题,但有一些封装的方法。 我想知道当全局对象所基于的值在 R6 实例中更新时是否可以更新全局对象? 这可能有点令人困惑,所以这里是一个例子。

x是我们希望用户使用的对象——它只是一个整数。 但是通过您分享的魔法,您将一个 R6 对象打包为一个属性,因此一些内部方法可用(例如x$update() )。 但是当您使用x$update(20)更新时,它只会更新self$x而不是x 。 是否可以通过超级赋值将更改传播到x的全局定义?

library(R6)

Foo <- R6Class(
  "Foo",
  public = list(
    x = 10,
    update = function(value) {
      self$x <- value
    }
  )
)

foo <- function() {
  obj <- Foo$new()
  structure(
    obj$x,
    impl = obj,
    class = "wrapped"
  )
}

`$.wrapped` <- function(x, name) {
  obj <- attr(x, "impl", exact = TRUE)
  obj[[name]]
}

`$<-.wrapped` <- function(x, name, value) {
  obj <- attr(x, "impl", exact = TRUE)
  obj[[name]] <- value
  obj$x
}

.DollarNames.wrapped <- function(x, pattern) {
  ls(attr(x, "impl", exact = TRUE))
}


x <- foo()
x
#> [1] 10
#> attr(,"impl")
#> <Foo>
#>   Public:
#>     clone: function (deep = FALSE) 
#>     update: function (value) 
#>     x: 10
#> attr(,"class")
#> [1] "wrapped"
x$update(20)
x
#> [1] 10
#> attr(,"impl")
#> <Foo>
#>   Public:
#>     clone: function (deep = FALSE) 
#>     update: function (value) 
#>     x: 20
#> attr(,"class")
#> [1] "wrapped"

我想它可以概括为就地修改,但在这种情况下,我们希望对象看起来和感觉起来像一个熟悉且常见的R对象,但有这些作用于对象的嵌入式方法。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

rappster picture rappster  ·  11评论

paulstaab picture paulstaab  ·  3评论

mb706 picture mb706  ·  4评论

wch picture wch  ·  8评论

kenarab picture kenarab  ·  8评论