Hai @wch ,
Apakah ada R6
setara dengan __call__
metode dunder di python
yang pada dasarnya membuat instance kelas dapat dipanggil seperti fungsi? Apakah ini fitur yang mungkin bisa ditambahkan? Apakah ada kepentingan dalam fitur ini?
Sesuatu seperti:
foo <- R6::R6Class(
"foo",
public = list(
.__call__ = function(args) {...}
)
)
bar <- foo$new()
bar(...)
Hampir semua metode dunder lainnya dapat diimplementasikan dalam R
dengan menulis metode S3
untuk obat generik yang ada, tetapi yang ini sepertinya perlu ditangani secara internal oleh R6
, jika itu mungkin sama sekali.
Saya cukup yakin bahwa di R, menggunakan ()
hanya akan berfungsi jika objeknya adalah suatu fungsi. Yang dapat Anda lakukan adalah mengembalikan fungsinya, dan menambahkan objek R6 sebagai atributnya.
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
Metode panggilan dunder terasa sangat tidak- R
-seperti, jadi saya pikir itu tidak mungkin. Ini adalah solusi yang menarik sekalipun. Sangat pintar. Terima kasih atas tanggapannya.
Saya kira kelemahannya adalah kurangnya bantuan pelengkapan otomatis untuk fungsi internal ( f$printx()
) dan args internal f$printx(arg)
, tampaknya tidak dapat dihindari.
Anda dapat menambahkan pelengkapan otomatis dengan ini:
.DollarNames.wrapped <- function(x, pattern) {
ls(attr(x, "impl", exact = TRUE))
}
Err, wah. Itu luar biasa. Sangat keren.
Hai @wch ,
Saya punya pertanyaan aneh lain yang mungkin bisa Anda pecahkan. Tapi yang satu ini sangat aneh.
Mirip dengan pertanyaan di atas terkait dengan memiliki objek yang terlihat dan terasa seperti objek normal, tetapi memiliki beberapa metode yang dienkapsulasi. Saya bertanya-tanya apakah mungkin untuk memperbarui objek global ketika nilai yang menjadi dasarnya diperbarui dalam contoh R6? Ini mungkin agak membingungkan jadi inilah contohnya.
x
adalah objek yang kita inginkan untuk digunakan oleh pengguna - Ini hanya bilangan bulat. Tetapi melalui keajaiban yang Anda bagikan, Anda mengemas objek R6 sebagai atribut sehingga beberapa metode internal tersedia (misalnya x$update()
). Tetapi ketika Anda membuat pembaruan dengan x$update(20)
, itu hanya memperbarui self$x
dan bukan x
. Apakah mungkin untuk menyebarkan perubahan ke definisi global x
, mungkin dengan penugasan super?
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"
Saya kira itu dapat diringkas sebagai modifikasi di tempat, tetapi dalam situasi di mana kita ingin objek terlihat dan terasa seperti objek R
familiar dan umum, tetapi memiliki metode yang disematkan ini yang bertindak pada objek.