web-dev-qa-db-ja.com

関数のソースコードを見るにはどうすればいいですか?

私はそれがどのように機能するかを見るために関数のソースコードを調べたいと思います。プロンプトに名前を入力することで関数を印刷できることを私は知っています。

> t
function (x) 
UseMethod("t")
<bytecode: 0x2332948>
<environment: namespace:base>

この場合、UseMethod("t")はどういう意味ですか?実際に使用されているソースコードを見つけるにはどうすればよいですか。たとえば、t(1:10)

UseMethodの場合とstandardGenericの場合とshowMethodswithの場合に違いはありますか?

> with
standardGeneric for "with" defined from package "base"

function (data, expr, ...) 
standardGeneric("with")
<bytecode: 0x102fb3fc0>
<environment: 0x102fab988>
Methods may be defined for arguments: data
Use  showMethods("with")  for currently available ones.

他のケースでは、私はRの関数が呼ばれているのを見ることができますが、私はそれらの関数のソースコードを見つけることができません。

> ts.union
function (..., dframe = FALSE) 
.cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE)
<bytecode: 0x36fbf88>
<environment: namespace:stats>
> .cbindts
Error: object '.cbindts' not found
> .makeNamesTs
Error: object '.makeNamesTs' not found

.cbindts.makeNamesTsのような関数を見つけるにはどうすればいいですか?

さらに他のケースでは、Rコードが少しありますが、ほとんどの作業は別の場所で行われているようです。

> matrix
function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) 
{
    if (is.object(data) || !is.atomic(data)) 
        data <- as.vector(data)
    .Internal(matrix(data, nrow, ncol, byrow, dimnames, missing(nrow), 
        missing(ncol)))
}
<bytecode: 0x134bd10>
<environment: namespace:base>
> .Internal
function (call)  .Primitive(".Internal")
> .Primitive
function (name)  .Primitive(".Primitive")

.Primitive関数が何をするのか、どうすればわかりますか?同様に、いくつかの関数は.C.Call.Fortran.External、または.Internalを呼び出します。それらのソースコードはどうやって見つけることができますか?

469
Joshua Ulrich

UseMethod("t")は、t()が( S3 )汎用関数であり、さまざまなオブジェクトクラスのメソッドを持つことを示しています。

S3方式発送システム

S3クラスの場合は、methods関数を使用して特定の一般的な関数またはクラスのメソッドを一覧表示できます。

> methods(t)
[1] t.data.frame t.default    t.ts*       

   Non-visible functions are asterisked
> methods(class="ts")
 [1] aggregate.ts     as.data.frame.ts cbind.ts*        cycle.ts*       
 [5] diffinv.ts*      diff.ts          kernapply.ts*    lines.ts        
 [9] monthplot.ts*    na.omit.ts*      Ops.ts*          plot.ts         
[13] print.ts         time.ts*         [<-.ts*          [.ts*           
[17] t.ts*            window<-.ts*     window.ts*      

   Non-visible functions are asterisked

「不可視関数にアスタリスクが付いている」とは、その関数がそのパッケージの名前空間からエクスポートされていないことを意味します。あなたはまだ:::関数(すなわちstats:::t.ts)を通して、またはgetAnywhere()を使ってそのソースコードを見ることができます。 getAnywhere()は関数がどのパッケージから来たのかを知る必要がないので便利です。

> getAnywhere(t.ts)
A single object matching ‘t.ts’ was found
It was found in the following places
  registered S3 method for t from namespace stats
  namespace:stats
with value

function (x) 
{
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
<bytecode: 0x294e410>
<environment: namespace:stats>

S4方式発送システム

S4システムは、より新しいメソッドディスパッチシステムであり、S3システムの代替手段です。これはS4関数の例です。

> library(Matrix)
Loading required package: lattice
> chol2inv
standardGeneric for "chol2inv" defined from package "base"

function (x, ...) 
standardGeneric("chol2inv")
<bytecode: 0x000000000eafd790>
<environment: 0x000000000eb06f10>
Methods may be defined for arguments: x
Use  showMethods("chol2inv")  for currently available ones.

出力はすでに多くの情報を提供しています。 standardGenericはS4関数の指標です。定義されたS4メソッドを確認するためのメソッドが役立ちます。

> showMethods(chol2inv)
Function: chol2inv (package base)
x="ANY"
x="CHMfactor"
x="denseMatrix"
x="diagonalMatrix"
x="dtrMatrix"
x="sparseMatrix"

getMethodは、次のいずれかの方法のソースコードを見るために使用できます。

> getMethod("chol2inv", "diagonalMatrix")
Method Definition:

function (x, ...) 
{
    chk.s(...)
    tcrossprod(solve(x))
}
<bytecode: 0x000000000ea2cc70>
<environment: namespace:Matrix>

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"

各メソッドに対してより複雑なシグネチャを持つメソッドもあります。

require(raster)
showMethods(extract)
Function: extract (package raster)
x="Raster", y="data.frame"
x="Raster", y="Extent"
x="Raster", y="matrix"
x="Raster", y="SpatialLines"
x="Raster", y="SpatialPoints"
x="Raster", y="SpatialPolygons"
x="Raster", y="vector"

これらのメソッドの1つのソースコードを見るには、シグネチャ全体を指定する必要があります。

getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") )

部分署名を指定するだけでは不十分です

getMethod("extract",signature="SpatialPolygons")
#Error in getMethod("extract", signature = "SpatialPolygons") : 
#  No method found for function "extract" and signature SpatialPolygons

未エクスポートの関数を呼び出す関数

ts.unionの場合、.cbindtsおよび.makeNamesTsは、stats名前空間からの未エクスポートの関数です。 :::演算子またはgetAnywhereを使用して、未エクスポートの関数のソースコードを表示できます。

> stats:::.makeNamesTs
function (...) 
{
    l <- as.list(substitute(list(...)))[-1L]
    nm <- names(l)
    fixup <- if (is.null(nm)) 
        seq_along(l)
    else nm == ""
    dep <- sapply(l[fixup], function(x) deparse(x)[1L])
    if (is.null(nm)) 
        return(dep)
    if (any(fixup)) 
        nm[fixup] <- dep
    nm
}
<bytecode: 0x38140d0>
<environment: namespace:stats>

コンパイル済みコードを呼び出す関数

"compile"は、 compiler パッケージによって作成されたバイトコンパイルされたRコードを参照しないことに注意してください。上記の出力の<bytecode: 0x294e410>行は、関数がバイトコンパイルされていることを示しています。それでも、Rコマンド行からソースを表示できます。

.C.Call.Fortran.External.Internal、または.Primitiveを呼び出す関数は、コンパイル済みコードのエントリポイントを呼び出すので、関数を完全に理解したい場合は、コンパイル済みコードのソースを調べる必要があります。 この GitHubのRソースコードのミラーリングは始めるのにまともな場所です。関数pryr::show_c_source.Internal.Primitiveの呼び出しのためにGitHubページに直接行くので便利なツールです。パッケージは.C.Call.Fortran、および.Externalを使用できます。しかし、.Internal.Primitiveは、Rインタプリタに組み込まれている関数を呼び出すために使用されるので、そうではありません。

上記の関数のいくつかへの呼び出しは、コンパイルされた関数を参照するために文字列の代わりにオブジェクトを使うかもしれません。そのような場合、オブジェクトはクラス"NativeSymbolInfo""RegisteredNativeSymbol"、または"NativeSymbol"です。そしてオブジェクトを印刷すると有用な情報が得られます。たとえば、optim.External2(C_optimhess, res$par, fn1, gr1, con)を呼び出します(C_optimhessではなく"C_optimhess"です)。 optimはstatsパッケージに含まれているので、stats:::C_optimhessと入力すると、呼び出されているコンパイル済み関数に関する情報を見ることができます。

パッケージ内のコンパイル済みコード

パッケージ内のコンパイル済みコードを表示したい場合は、パッケージソースをダウンロード/解凍する必要があります。インストールされているバイナリでは不十分です。パッケージのソースコードは、パッケージが最初にインストールされたのと同じCRAN(またはCRAN互換)リポジトリから入手できます。 download.packages()関数はあなたに代わってパッケージソースを取得できます。

download.packages(pkgs = "Matrix", 
                  destdir = ".",
                  type = "source")

これにより、Matrixパッケージのソースバージョンがダウンロードされ、対応する.tar.gzファイルが現在のディレクトリに保存されます。コンパイルされた関数のソースコードは、圧縮されていないファイルのsrcディレクトリにあります。解凍と解凍のステップは、Rの外部、またはuntar()関数を使用してR内から実行できます。ダウンロードと展開のステップを1回の呼び出しにまとめることができます(この方法では一度に1つのパッケージしかダウンロードおよび解凍できません)。

untar(download.packages(pkgs = "Matrix",
                        destdir = ".",
                        type = "source")[,2])

あるいは、パッケージ開発が公にホストされている場合(例えば GitHubR-Forge 、または RForge.net など)、おそらくソースコードをオンラインで閲覧することができます。

基本パッケージ内のコンパイル済みコード

特定のパッケージは「基本」パッケージと見なされます。これらのパッケージはRに同梱されており、それらのバージョンはRのバージョンにロックされています。例としては、basecompilerstats、およびutilsがあります。そのため、これらは上記のようにCRANの個別のダウンロード可能パッケージとしては利用できません。そうではなく、それらは/src/library/の下の個々のパッケージディレクトリ内のRソースツリーの一部です。 Rソースへのアクセス方法は次のセクションで説明します。

Rインタプリタに組み込まれたコンパイル済みコード

Rインタプリタに組み込まれているコードを見たい場合は、Rソースをダウンロード/解凍する必要があります。あるいは、R Subversionリポジトリ または Winston Changのgithubミラー からソースをオンラインで見ることができます。

Uwe Liggesの Rニュース記事(PDF) (p。43)は、.Internalおよび.Primitive関数のソースコードの表示方法に関する一般的な参考資料です。基本的な手順は、まずsrc/main/names.cで関数名を探し、次にsrc/main/*内のファイルで "C-entry"という名前を検索することです。

453
Joshua Ulrich

この質問とその重複についての他の答えに加えて、どのパッケージに入っているのかを知る必要なしに、パッケージ関数のソースコードを取得する良い方法があります。 randomForest::rfcv()のソースが欲しい場合:

ポップアップウィンドウで 表示/編集 それにアクセスします。

edit(getAnywhere('rfcv'), file='source_rfcv.r')

別のファイルにリダイレクトする

capture.output(getAnywhere('rfcv'), file='source_rfcv.r')
89
smci

あなたがdebug()関数を使ってデバッグするとき、それは明らかにされます。 t() transpose関数の基礎となるコードを見たいとしましょう。 「t」と入力するだけでは、あまりわかりません。

>t 
function (x) 
UseMethod("t")
<bytecode: 0x000000003085c010>
<environment: namespace:base>

しかし、 'debug(functionName)'を使用すると、基礎となるコードが明らかになり、内部は不要になります。

> debug(t)
> t(co2)
debugging in: t(co2)
debug: UseMethod("t")
Browse[2]> 
debugging in: t.ts(co2)
debug: {
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
Browse[3]> 
debug: cl <- oldClass(x)
Browse[3]> 
debug: other <- !(cl %in% c("ts", "mts"))
Browse[3]> 
debug: class(x) <- if (any(other)) cl[other]
Browse[3]>  
debug: attr(x, "tsp") <- NULL
Browse[3]> 
debug: t(x)

編集: debugonce()はundebug()を使わなくても同じことを実現します。

25
Selva

これが主な回答の流れにどのように適合するかはわかりませんでしたが、しばらくの間私を困惑させたので、ここに追加します。

中置演算子

基本の中置演算子のソースコード(%%%*%%in%など)を見るには、getAnywhereを使います。

getAnywhere("%%")
# A single object matching ‘%%’ was found
# It was found in the following places
#   package:base
#   namespace:base
#  with value
#
# function (e1, e2)  .Primitive("%%")

主な答えは、どのようにしてミラーを使ってより深く掘り下げるかをカバーしています。

18
MichaelChirico

非プリミティブ関数の場合、R baseは関数本体を返すbody()という関数を含みます。例えば、print.Date()関数のソースは見ることができます:

body(print.Date)

これを生成します:

{
    if (is.null(max)) 
        max <- getOption("max.print", 9999L)
    if (max < length(x)) {
        print(format(x[seq_len(max)]), max = max, ...)
        cat(" [ reached getOption(\"max.print\") -- omitted", 
            length(x) - max, "entries ]\n")
    }
    else print(format(x), max = max, ...)
    invisible(x)
}

スクリプトで作業していて、機能コードを文字ベクトルとして使用したい場合は、それを入手できます。

capture.output(print(body(print.Date)))

あなたを得るでしょう:

[1] "{"                                                                   
[2] "    if (is.null(max)) "                                              
[3] "        max <- getOption(\"max.print\", 9999L)"                      
[4] "    if (max < length(x)) {"                                          
[5] "        print(format(x[seq_len(max)]), max = max, ...)"              
[6] "        cat(\" [ reached getOption(\\\"max.print\\\") -- omitted\", "
[7] "            length(x) - max, \"entries ]\\n\")"                      
[8] "    }"                                                               
[9] "    else print(format(x), max = max, ...)"                           
[10] "    invisible(x)"                                                    
[11] "}"     

なぜ私はそのようなことをしたいのでしょうか?リストに基づいてカスタムS3オブジェクト(x、ここでclass(x) = "foo")を作成していました。リストメンバの1つ( "fun"という名前)は関数で、私はprint.foo()に関数のソースコードをインデント表示させたいと思いました。だから私はprint.foo()で次のスニペットになった:

sourceVector = capture.output(print(body(x[["fun"]])))
cat(paste0("      ", sourceVector, "\n"))

これはx[["fun"]]に関連したコードを字下げして表示します。

17
Geoffrey Poole

R editにはとても便利な関数があります

new_optim <- edit(optim)

Rのoptimで指定されたエディタを使用してoptionsのソースコードを開き、それを編集して変更した関数をnew_optimに割り当てることができます。この関数はコードを表示したりコードをデバッグしたりするのにとても好きです。例えば、メッセージや変数を印刷したり、さらに調べるためにそれらをグローバル変数に割り当てることさえできます(もちろんdebugを使用できます)。

ソースコードを見たいだけで、面倒な長いソースコードをコンソールに表示したくない場合は、次のようにします。

invisible(edit(optim))

明らかに、これはC/C++やFortranのソースコードを見るのには使えません。

ところで、editはlist、matrixなどのような他のオブジェクトを開くことができます。そしてそれは属性と共にデータ構造も示します。関数deは、行列やデータフレームを修正して新しいものを返すために(GUIがサポートしていれば)Excelのようなエディタを開くために使うことができます。これは便利なこともありますが、通常は、特に行列が大きい場合は避けるべきです。

9
Eric

関数がC/C++/Fortranではなく純粋なRで書かれている限り、以下を使用することができます。さもなければ最もよい方法は デバッグ そして " jump into "を使うことです:

> functionBody(functionName)
6
MCH

View([function_name]) - 例えば。 View(mean)必ず大文字の[V]を使ってください。読み取り専用コードがエディタで開きます。

4
Koo

また、S3汎用のprint.function()を使ってコンソールに関数を書き込もうとすることもできます。

4
strboul

RStudioには、(少なくとも)3つの方法があります。

  1. カーソルがいずれかの機能にある間にF2キーを押します。
  2. CtrlキーまたはCommandキーを押しながら機能名をクリックします。
  3. Viewname __(function_name)(上記のとおり)

新しいペインがソースコードと共に開きます。 .Primitiveまたは.Cに到達したら、別の方法が必要になるでしょう、ごめんなさい。

3
Arthur Yip