http://qiita.com/items/325bdf48f4f4885a86f1 と
http://qiita.com/items/35184390984975ec7c6d の続き。
余談ですが、「環境」という言葉から、ちょっと考えこむと「自分の実行環境はどこか?」しいては「自分が今どの環境の中にいるのか」ということを考えてしまいがちです。これはやめといた方がいいです。
必要なのは、「今自分の隣にいるおばちゃんは誰か」です。これで大分すっきりして気が楽になります。
environment()
は、「今自分がどの環境のかなにいるのか教えてくれる関数」ではなくて、「今隣にいるおばちゃんは誰か」を教えてくれる関数です。
##1-6 関数の環境
関数は環境を持っています。これは関数呼び出し時に作られる環境とは異なります。
「持っています」というのが誤解の元なんだよなあ。
イメージとしては、困ったときに相談するおばちゃんをメモっとく、という感じです。
関数を定義すると、
> f <- function() {
+ print(environment())
+ print(parent.env(environment()))
+ }
> environment(f)
<environment: R_GlobalEnv>
という感じで、f
の環境は、この場合は.GlobalEnv
です。
> f()
<environment: 0x1169ecb88> #これ呼び出し時に作られたおばちゃん
<environment: R_GlobalEnv> #そのおばちゃんが困ったら相談するおばちゃん
という風に考えると、関数というのは、
- 呼び出された時におばちゃん一人つくって、あなたの隣におく。
- そのおばちゃんに、困ったときに相談するおばちゃんを教えておく。
という能力を持った人です。
##1-7 関数の環境 ≠ 定義時の環境
デフォルトでは、関数の環境、つまり関数がメモったおばちゃんは、関数が定義された時の環境です。
> environment()
<environment: R_GlobalEnv> # 今の環境(あなたの隣のおばちゃん)
> f <- function() {}
> environment(f)
<environment: R_GlobalEnv> # 関数fがメモったのはその環境
> g <- function() {
+ print(environment()) # *1
+ h <- function() {}
+ print(environment(h)) # *2
+ }
> g()
<environment: 0x11726f608> # *1: 今の環境(呼び出し時に作られたやつ)
<environment: 0x11726f608> # *2: 関数hがメモった環境
ただこれ、あとで変えられるんですね。つまり、関数に「困ったらこのおばちゃんに相談するように言っといてねー」ってあとから出来る。
> f <- function() {
+ parent.env(environment()) # 実行時の環境の親を表示(自分の隣にいるおばちゃんの相談相手)
+ }
> environment(f)
<environment: R_GlobalEnv> # デフォルトでは相談相手は.GlobalEnv
> f()
<environment: R_GlobalEnv> # です。
>
> e <- new.env() # 新しい環境を作成。おばちゃんひとり作ったと思っとけばいい。
> e
<environment: 0x1171ea1f8>
>
> environment(f) <- e # 「困ったらこのおばちゃんに聞いとけ」メモ
> environment(f)
<environment: 0x1171ea1f8> # 変更されてる
> f()
<environment: 0x1171ea1f8> # こっちも
あーややこしい。
なので、私はこう考えています。
##1-8 関数にまつわる3つの環境
- 呼び出し時に作られる環境
- 呼び出し時に作られる環境の親となる環境
- 関数がある環境
おばちゃんで言い換えると
- 呼び出し時にボワッと作られるおばちゃん
- 1.のおばちゃんが困ったときに相談する相手
- 関数を持ってるおばちゃん
この3.がまた厄介で、「関数の環境」と「関数のある環境」は異なります。
これが、http://obeautifulcode.com/R/How-R-Searches-And-Finds-Stuff/ のブログの実践と点線、package:hoge
とnamespace:hoge
につながってきます。
つづく。