ls()についてのもうちょっと回りくどい説明

これのもうちょっと回りくどい版の記事を書きます。

ls()

ls()は、指定した環境中にあるオブジェクト名の一覧を取得する関数です。

引数に何も指定しなければ、その関数を実行した環境を調べます。 つまり、コンソールで実行した場合は、ユーザがいろんな変数を定義したりする「グローバル環境」を調べます。 グローバル環境には、はじめは何もありません。

ls()
#> character(0)

ここで、xという変数を定義すると、たしかにxが増えるのがわかります。

x <- 1

ls()
#> [1] "x"

どの環境をls()したいか指定することもできます。 Rにはグローバル環境を指す.GlobalEnvという変数があらかじめ定義されているのでそれを指定してみましょう。

ls(.GlobalEnv)
#> [1] "x"

上と同じ結果が得られました。 ここでは環境そのものを引数に渡しましたが、実はls()に環境を指定する方法は他にもあります。 以下のように文字列を指定しても同じようにグローバル環境を調べてくれます。また、数字を指定することもできます。

ls(".GlobalEnv")
#> [1] "x"
ls(1)
#> [1] "x"

これはどういう仕組みなのでしょう。?lsによると、

The name argument can specify the environment from which object names are taken in one of several forms: as an integer (the position in the search list); as the character string name of an element in the search list; or as an explicit environment

と書かれています。「search list」というのは、オブジェクトを探すときに探索される環境のリストで、search()で見ることができるものです。 文字列を指定したときにはこの中で一致する名前の環境、数字を指定したときはこの並びの中で指定した順番の環境が使われます。

search()
#> [1] ".GlobalEnv"        "tools:rstudio"     "package:stats"     "package:graphics"  "package:grDevices"
#> [6] "package:utils"     "package:datasets"  "package:methods"   "Autoloads"         "package:base"     

まとめると、ls()への環境の指定の仕方は

  1. 環境そのものを渡す
  2. 環境の名前を文字列で渡す
  3. 環境の位置を数字で渡す

の3つがあります。これらそれぞれにenvirnameposという引数を使い分けないといけない時代がかつてあったようですが、 今は「Mostly there for back compatibility.」と書かれているので、引数の名前は指定せず適当にls()に渡してしまって大丈夫みたいです。

環境

さて、「オブジェクトを探すときに探索される環境」と書きましたが、これはどういうことなのでしょう。 たとえば、先ほどはxを定義しました。コンソールにxと打った時、Rはまず.GlobalEnvの中を探索します。そこで同じ名前のものが見つかるのでそれを使います。

x
#> [1] 1

しかし、たとえばheadというオブジェクトはグローバル環境にはありません。 なければ、「search list」の1つ上、つまりtools:rstudioを探します。 なければ次に、pacckage:statsを探します。 ...という具合の探索を繰り返し、lspackage:utilsで見つかります。

"head" %in% ls("package:utils")
#> [1] TRUE

という感じの話は、パンダ本の8章とか9章あたりに書いてあった気がするので買って読みましょう(ステマ)。

Rプログラミング本格入門: 達人データサイエンティストへの道

Rプログラミング本格入門: 達人データサイエンティストへの道

さて、このpackage:utilsというのはutilsパッケージの環境です。しかし、utilsパッケージで定義されている*1オブジェクトすべてがここに含まれているわけではありません。 みなさんご存知のように、パッケージにはlibrary()でパッケージを読み込めば使えるようになる関数と、:::で呼び出さないと使えない関数とがあります。 package:utilsというのはutilsパッケージのオブジェクトのうち、前者、つまりエクスポートされているもののみを集めた名前空間なのです。

後者は、パッケージ内のオブジェクトすべてを含んでいます。この環境を取得する方法はいろいろありますが、たとえば、environment()という関数で、ある関数やフォーミュラがどの環境にあるか調べることができます。 これをheadに使ってみましょう。

environment(head)
#> <environment: namespace:utils>

namespace:utilsというのが出てきました。これは、utilsパッケージ内で定義されているすべてのオブジェクトを含んでいます。 ls()した結果を比べてみると分かると思います。

length(ls(environment(head)))
#> [1] 492
length(ls("package:utils"))
#> [1] 241

まとめ

みたいな感じの事をぐだぐだ説明するにはr-wakalangの余白が狭すぎるなあ、とか思ったりします。 どうするのがいいんですかね...。とりあえず引き続き質問・意見お待ちしています。

*1:「定義されている」という表現はたぶん正確じゃないですが、まあ説明のためということで...