HIRO: R Advent Calendar 2014
 R Advent Calendar 2014 14日目の記事です
 R6の解説そのまま使わせて頂きました
http://cran.r-project.org/web/packages/R6のVignettes
http://stackoverflow.com/questions/tagged/r6
 なぜ今更 R6 Classes?
 JapanR 2014で「すごく使いやすい」と聞
いたから
 S4, R5が使いにくかったから(個人の意見です)
 記事にするネタが無くて困っていたから…
HIRO: R Advent Calendar 2014
HIRO: R Advent Calendar 2014
 他言語のようなオブジェクト指向
 R6パッケージを読み込む
 特徴
 参照セマンティクス
 active bindings
 public/private メソッド
 継承(スーパークラスとサブクラス)
HIRO: R Advent Calendar 2014
library(R6)
Person <- R6Class("Person",
public = list(
name = NA,
hair = NA,
initialize = function(name, hair) {
if (!missing(name)) self$name <- name
if (!missing(hair)) self$hair <- hair
self$greet()
},
set_hair = function(val) {
self$hair <- val
},
greet = function() {
cat(paste0("Hello, my name is ", self$name, ".¥n"))
}
)
)
Person classを定義する
フィールド
メソッド
コンストラクタ
publicメンバは
selfを使って呼
び出す
HIRO: R Advent Calendar 2014
ann <- Person$new("Ann", "black")
> Hello, my name is Ann.
ann
> <Person>
> Public:
> greet: function
> hair: black
> initialize: function
> name: Ann
> set_hair: function
Person classのインスタンス化
ann$hair
> black
ann$set_hair <- “red”
#または
ann$hair <- “red”
ann$hair
> red
publicメンバへのアクセス
HIRO: R Advent Calendar 2014
Numbers <- R6Class("Numbers",
public = list(
x = 100
),
active = list(
x2 = function(value) {
if (missing(value)) return(self$x * 2)
else self$x <- value/2
},
rand = function() rnorm(1)
)
)
Number classの定義 publicメンバへのアクセス
n <- Numbers$new()
n$x
> [1] 100
n$rand
#> [1] 0.2648
n$rand
#> [1] 2.171
n$rand <- 3
#> Error: unused argument
(quote(3))
active bindingsへのアクセス
active bindings: アクセスされる
たびに実行される
HIRO: R Advent Calendar 2014
Queue <- R6Class("Queue",
public = list(
initialize = function(...) {
for (item in list(...)) {
self$push(item)
}
},
push = function(x) {
private$queue <- c(private$queue, list(x))
invisible(self)
},
pop = function() {
if (private$length() == 0) return(NULL)
# Can use private$queue for explicit access
head <- private$queue[[1]]
private$queue <- private$queue[-1]
head
}
),
private = list(
queue = list(),
length = function() base::length(private$queue)
)
)
今度の例はprivateメンバを含むクラス
push(“something”)の度にキューが伸びる
pop()で最初に入ったものから1つずつ取り
除かれる
HIRO: R Advent Calendar 2014
q <- Queue$new(5, 6, "foo")
q$push("something")
q$push("another thing")
#q$push("something")$push("another thing"))でも同じ結果
q$pop()
> [1] 5
q$queue
> NULL
q$length()
> Error: attempt to apply non-function
Queue classのインスタンス化
チェーンも可
publicメンバにはアクセス可能
privateメンバにはアクセスできない
HIRO: R Advent Calendar 2014
q <- Queue$new(5, 6, "foo")
q$push("something")
q$push("another thing")
q$push(17)
#q$push("something")$push("another thing")$push(17)
#でも同じ結果
q$pop()
> [1] 5
q$pop()
> [1] 6
Queue classのインスタンス化
HIRO: R Advent Calendar 2014
HistoryQueue <- R6Class("HistoryQueue",
inherit = Queue,
public = list(
show = function() {
cat("Next item is at index", private$head_idx + 1,
"¥n")
for (i in seq_along(private$queue)) {
cat(i, ": ", private$queue[[i]], "¥n", sep = "")
}
},
pop = function() {
if (private$length() - private$head_idx == 0)
return(NULL)
private$head_idx <<- private$head_idx + 1
private$queue[[private$head_idx]]
}
),
private = list(
head_idx = 0
)
)
Queue classの継承
show() の追加
method() のオーバーライド
HIRO: R Advent Calendar 2014
hq <- HistoryQueue$new(5, 6, "foo")
hq$show()
> Next item is at index 1
> 1: 5
> 2: 6
> 3: foo
hq$pop()
> [1] 5
hq$show()
> Next item is at index 2
> 1: 5
> 2: 6
> 3: foo
hq$pop()
> [1] 6
Queueのサブクラスである
HistoryQueueのインスタンス化
HIRO: R Advent Calendar 2014
CountingQueue <- R6Class("CountingQueue",
inherit = Queue,
public = list(
push = function(x) {
private$total <<- private$total + 1
super$push(x)
},
get_total = function() private$total
),
private = list(
total = 0
)
)
cq <- CountingQueue$new("x", "y")
cq$get_total()
> [1] 2
cq$push("z")
cq$pop()
> [1] "x"
cq$pop()
> [1] "y"
cq$get_total()
> [1] 3
Queue classの継承
スーパークラスのメソッドをsuper$で呼び出し
HIRO: R Advent Calendar 2014
SimpleClass <- R6Class("SimpleClass",
public = list(x = NULL)
)
NonSharedField <- R6Class("NonSharedField",
public = list(
e = NULL,
initialize = function() e <<- SimpleClass$new()
)
)
n1 <- NonSharedField$new()
n1$e$x <- 1
n2 <- NonSharedField$new()
n2$e$x <- 2
# n2$e$x does not affect n1$e$x
n1$e$x
> [1] 1
initializeメソッドの中で
オブジェクト参照
*initializeメソッドの中ではなく
直接設定される場合、すべてで共有
されてしまう(左の例の場合、
n1$e$x = 2 となる)
HIRO: R Advent Calendar 2014
NP <- R6Class("NP",
portable = FALSE,
public = list(
x = NA,
getx = function() x,
setx = function(value) x <<- value
)
)
np <- NP$new()
np$setx(10)
np$getx()
> [1] 10
P <- R6Class("P",
portable = TRUE, # This is default
public = list(
x = NA,
getx = function() self$x,
setx = function(value) self$x <- value
)
)
p <- P$new()
p$setx(10)
p$getx()
> [1] 10
non-portable classの場合のみ
selfの代わりに <<- 使用可
Portable class: portable=TRUE
・異なるパッケージ間でも継承
・メンバへのアクセスには、(public) self$x もしくは <<- や private$y が必要
HIRO: R Advent Calendar 2014
clsTrnR6 <- R6Class("clsTrnR6",
lock=FALSE,
public = list(
x = NA,
initialize = function(x) {
self$x <- x
},
push_function = function(name, meth) {
self[[name]] <- meth
environment(self[[name]]) <-
environment(self$push_function)
}
)
)
clsR6 <- clsTrnR6$new(x=4)
clsR6$x
#[1] 4
clsR6$push_function("predict", function(y) y*self$x)
clsR6$predict(11)
メソッドの追加
HIRO: R Advent Calendar 2014
lock = FALSE
A <- R6Class("A", public = list(
initialize = function() {
reg.finalizer(self,
function(e) print("Finalizer has been called!"),
onexit = TRUE)
}
))
A$new()
1+1
invisible(gc()
> "Finalizer has been called!"
initializeの中で
ファイナライザを呼び出し
最後の処理の結果が.Last.valueに入るので
何か別の処理をする
gc()で終了
HIRO: R Advent Calendar 2014
 ありがとうございました m(_ _)m
 誤訳・誤解等ご指摘ください
 あっても大目に見て下さい…
HIRO: R Advent Calendar 2014

R6 classes

  • 1.
    HIRO: R AdventCalendar 2014
  • 2.
     R AdventCalendar 2014 14日目の記事です  R6の解説そのまま使わせて頂きました http://cran.r-project.org/web/packages/R6のVignettes http://stackoverflow.com/questions/tagged/r6  なぜ今更 R6 Classes?  JapanR 2014で「すごく使いやすい」と聞 いたから  S4, R5が使いにくかったから(個人の意見です)  記事にするネタが無くて困っていたから… HIRO: R Advent Calendar 2014
  • 3.
    HIRO: R AdventCalendar 2014
  • 4.
     他言語のようなオブジェクト指向  R6パッケージを読み込む 特徴  参照セマンティクス  active bindings  public/private メソッド  継承(スーパークラスとサブクラス) HIRO: R Advent Calendar 2014
  • 5.
    library(R6) Person <- R6Class("Person", public= list( name = NA, hair = NA, initialize = function(name, hair) { if (!missing(name)) self$name <- name if (!missing(hair)) self$hair <- hair self$greet() }, set_hair = function(val) { self$hair <- val }, greet = function() { cat(paste0("Hello, my name is ", self$name, ".¥n")) } ) ) Person classを定義する フィールド メソッド コンストラクタ publicメンバは selfを使って呼 び出す HIRO: R Advent Calendar 2014
  • 6.
    ann <- Person$new("Ann","black") > Hello, my name is Ann. ann > <Person> > Public: > greet: function > hair: black > initialize: function > name: Ann > set_hair: function Person classのインスタンス化 ann$hair > black ann$set_hair <- “red” #または ann$hair <- “red” ann$hair > red publicメンバへのアクセス HIRO: R Advent Calendar 2014
  • 7.
    Numbers <- R6Class("Numbers", public= list( x = 100 ), active = list( x2 = function(value) { if (missing(value)) return(self$x * 2) else self$x <- value/2 }, rand = function() rnorm(1) ) ) Number classの定義 publicメンバへのアクセス n <- Numbers$new() n$x > [1] 100 n$rand #> [1] 0.2648 n$rand #> [1] 2.171 n$rand <- 3 #> Error: unused argument (quote(3)) active bindingsへのアクセス active bindings: アクセスされる たびに実行される HIRO: R Advent Calendar 2014
  • 8.
    Queue <- R6Class("Queue", public= list( initialize = function(...) { for (item in list(...)) { self$push(item) } }, push = function(x) { private$queue <- c(private$queue, list(x)) invisible(self) }, pop = function() { if (private$length() == 0) return(NULL) # Can use private$queue for explicit access head <- private$queue[[1]] private$queue <- private$queue[-1] head } ), private = list( queue = list(), length = function() base::length(private$queue) ) ) 今度の例はprivateメンバを含むクラス push(“something”)の度にキューが伸びる pop()で最初に入ったものから1つずつ取り 除かれる HIRO: R Advent Calendar 2014
  • 9.
    q <- Queue$new(5,6, "foo") q$push("something") q$push("another thing") #q$push("something")$push("another thing"))でも同じ結果 q$pop() > [1] 5 q$queue > NULL q$length() > Error: attempt to apply non-function Queue classのインスタンス化 チェーンも可 publicメンバにはアクセス可能 privateメンバにはアクセスできない HIRO: R Advent Calendar 2014
  • 10.
    q <- Queue$new(5,6, "foo") q$push("something") q$push("another thing") q$push(17) #q$push("something")$push("another thing")$push(17) #でも同じ結果 q$pop() > [1] 5 q$pop() > [1] 6 Queue classのインスタンス化 HIRO: R Advent Calendar 2014
  • 11.
    HistoryQueue <- R6Class("HistoryQueue", inherit= Queue, public = list( show = function() { cat("Next item is at index", private$head_idx + 1, "¥n") for (i in seq_along(private$queue)) { cat(i, ": ", private$queue[[i]], "¥n", sep = "") } }, pop = function() { if (private$length() - private$head_idx == 0) return(NULL) private$head_idx <<- private$head_idx + 1 private$queue[[private$head_idx]] } ), private = list( head_idx = 0 ) ) Queue classの継承 show() の追加 method() のオーバーライド HIRO: R Advent Calendar 2014
  • 12.
    hq <- HistoryQueue$new(5,6, "foo") hq$show() > Next item is at index 1 > 1: 5 > 2: 6 > 3: foo hq$pop() > [1] 5 hq$show() > Next item is at index 2 > 1: 5 > 2: 6 > 3: foo hq$pop() > [1] 6 Queueのサブクラスである HistoryQueueのインスタンス化 HIRO: R Advent Calendar 2014
  • 13.
    CountingQueue <- R6Class("CountingQueue", inherit= Queue, public = list( push = function(x) { private$total <<- private$total + 1 super$push(x) }, get_total = function() private$total ), private = list( total = 0 ) ) cq <- CountingQueue$new("x", "y") cq$get_total() > [1] 2 cq$push("z") cq$pop() > [1] "x" cq$pop() > [1] "y" cq$get_total() > [1] 3 Queue classの継承 スーパークラスのメソッドをsuper$で呼び出し HIRO: R Advent Calendar 2014
  • 14.
    SimpleClass <- R6Class("SimpleClass", public= list(x = NULL) ) NonSharedField <- R6Class("NonSharedField", public = list( e = NULL, initialize = function() e <<- SimpleClass$new() ) ) n1 <- NonSharedField$new() n1$e$x <- 1 n2 <- NonSharedField$new() n2$e$x <- 2 # n2$e$x does not affect n1$e$x n1$e$x > [1] 1 initializeメソッドの中で オブジェクト参照 *initializeメソッドの中ではなく 直接設定される場合、すべてで共有 されてしまう(左の例の場合、 n1$e$x = 2 となる) HIRO: R Advent Calendar 2014
  • 15.
    NP <- R6Class("NP", portable= FALSE, public = list( x = NA, getx = function() x, setx = function(value) x <<- value ) ) np <- NP$new() np$setx(10) np$getx() > [1] 10 P <- R6Class("P", portable = TRUE, # This is default public = list( x = NA, getx = function() self$x, setx = function(value) self$x <- value ) ) p <- P$new() p$setx(10) p$getx() > [1] 10 non-portable classの場合のみ selfの代わりに <<- 使用可 Portable class: portable=TRUE ・異なるパッケージ間でも継承 ・メンバへのアクセスには、(public) self$x もしくは <<- や private$y が必要 HIRO: R Advent Calendar 2014
  • 16.
    clsTrnR6 <- R6Class("clsTrnR6", lock=FALSE, public= list( x = NA, initialize = function(x) { self$x <- x }, push_function = function(name, meth) { self[[name]] <- meth environment(self[[name]]) <- environment(self$push_function) } ) ) clsR6 <- clsTrnR6$new(x=4) clsR6$x #[1] 4 clsR6$push_function("predict", function(y) y*self$x) clsR6$predict(11) メソッドの追加 HIRO: R Advent Calendar 2014 lock = FALSE
  • 17.
    A <- R6Class("A",public = list( initialize = function() { reg.finalizer(self, function(e) print("Finalizer has been called!"), onexit = TRUE) } )) A$new() 1+1 invisible(gc() > "Finalizer has been called!" initializeの中で ファイナライザを呼び出し 最後の処理の結果が.Last.valueに入るので 何か別の処理をする gc()で終了 HIRO: R Advent Calendar 2014
  • 18.
     ありがとうございました m(__)m  誤訳・誤解等ご指摘ください  あっても大目に見て下さい… HIRO: R Advent Calendar 2014