r6 classes

18
HIRO: R Advent Calendar 2014

Upload: hiroki84

Post on 12-Jul-2015

881 views

Category:

Technology


4 download

TRANSCRIPT

Page 1: R6 classes

HIRO: R Advent Calendar 2014

Page 2: R6 classes

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

Page 3: R6 classes

HIRO: R Advent Calendar 2014

Page 4: R6 classes

他言語のようなオブジェクト指向

R6パッケージを読み込む

特徴

参照セマンティクス

active bindings

public/private メソッド

継承(スーパークラスとサブクラス)

HIRO: R Advent Calendar 2014

Page 5: R6 classes

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

Page 6: R6 classes

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

Page 7: R6 classes

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

Page 8: R6 classes

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

Page 9: R6 classes

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

Page 10: R6 classes

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

Page 11: R6 classes

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

Page 12: R6 classes

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

Page 13: R6 classes

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

Page 14: R6 classes

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

Page 15: R6 classes

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

Page 16: R6 classes

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

Page 17: R6 classes

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

Page 18: R6 classes

ありがとうございました m(_ _)m

誤訳・誤解等ご指摘ください

あっても大目に見て下さい…

HIRO: R Advent Calendar 2014