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


551

関数のソースコードを調べて、その機能を確認します。関数名をプロンプトに入力して、関数を出力できることを知っています。

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

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

私が見たときとの間に差があるUseMethodと、私が見たときstandardGenericshowMethods場合と同様に、with

> 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。それらのソースコードを見つけるにはどうすればよいですか?




回答:


518

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.

出力にはすでに多くの情報が含まれています。standardGenericS4関数のインジケーターです。定義された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"

これらのメソッドのいずれかのソースコードを表示するには、署名全体を指定する必要があります。

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>

コンパイルされたコードを呼び出す関数

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

機能その呼び出し.C.Call.Fortran.External.Internal、または.Primitiveあなたが完全に機能を理解したい場合は、コンパイルされたコードのソースを見てする必要がありますので、コンパイルされたコードにエントリーポイントを呼び出しています。この RソースコードのGitHubミラーは、開始するのに適切な場所です。この関数pryr::show_c_sourceは、GitHubページに直接アクセスして呼び出すことができるので、便利なツールに.Internalなり.Primitiveます。パッケージには、使用することができ.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は、圧縮されていないtarファイルのディレクトリにあります。圧縮解除と風袋引きの手順はR、の外部で、または関数Rを使用して内部から実行できますuntar()。ダウンロードと拡張のステップを1つの呼び出しに組み合わせることができます(この方法では、一度に1つのパッケージのみをダウンロードして解凍できます)。

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

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

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

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

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

Rインタープリターに組み込まれているコードを表示する場合は、Rソースをダウンロード/アンパックする必要があります。または、R SubversionリポジトリまたはWinston Changのgithubミラーを介してソースをオンラインで表示できます。

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


71
を使用する場合RStudioF2キーを押すと、テキストカーソルが置かれている関数のソースをプルしようとします。
アリB.フリードマン

1
@Ari B. Friedmanこの遅い質問でごめんなさい。RStudioは、関数またはCで書かれた関数のCソースコードもプルしますか?ありがとう
Sunny

3
@Samir私はそれが単なるRソースであると信じています。
Ari B. Friedman、

@ AriB.Friedman-ありがとうAri、これは便利です。私の場合、私はまだ答えに示されている知識が必要でした(scaleこれはS3です-取得UseMethod("scale")して使用しましたgetAnywhere(scale.default))。しかし、単純な関数はうまく機能します。
Tomasz Gandor

2
模倣はお世辞の誠実な形です私はこの回答/ wikiが最初に来たと思います:)この前にrfaqs.com/source-code-of-r-method
JimLohse

94

この質問とその重複に関する他の回答に加えて、パッケージがどのパッケージにあるかを知る必要なく、パッケージ関数のソースコードを取得するための良い方法を次に示しますrandomForest::rfcv()

表示/編集ポップアップウィンドウでそれを:

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

するために、別のファイルにリダイレクトします

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

確かに、getAnywhereは呼ばれている必要があります何かの名前の別の奇抜なRの選択であるfindOnSearchPathまたは類似。
smci 2015

1
私が望んでいたものに近づいたので、この回答を賛成します。RStudioで実際に欲しかったのはView(foo)、はfoo、すでにロードされているパッケージの関数でした。
Sigfried

1
@Sigfried: edit()(ユーザーの選択の)テキストエディタを開き、一方View()のためのエクセル型のスプレッドシートビューア開きデータを、後者は(マルチ柱状)のデータを閲覧するための良いですが、おもちゃの長さ以外のコードのために、通常はひどいです。一般的に、私がヒントとしてたとえば、私は、関数を参照するときやりたいまず最初にスキップ/全てのarg-解析すると、デフォルト・アクション・ロジックアウト崩壊/ダミー、関数が実際にものを見るためにある
smci

25

debug()関数を使用してデバッグすると明らかになります。基になるコードをt()転置関数で確認するとします。「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()を使用せずに同じことを実行します


受け入れられた回答で与えられたものと比較したこのメソッドの欠点は、機能する関数呼び出しが必要であることです(すべての必要なパラメーターが許容可能に指定されています)。コードの最初のブロックに加えて、実行時に各ブロックも取得します。これはデバッグには最適ですが、ソースを取得するだけでは最適ではありません。
ブライアンディッグス2014

はい、最適ではありません。しかし、賢い場合は、組み込み関数のソースをすばやく正確に取得できます。
セルバ2014

2
このインスタンスのdebugonce代わりにを使用することもお勧めしdebugます。
Joshua Ulrich

20

非プリミティブ関数の場合、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オブジェクト(xclass(x) = "foo"リストに基づいて、ここで)を作成していました。リストメンバーの1つ( "fun"という名前)は関数でありprint.foo()、関数のソースコードをインデントして表示したいと思いました。だから私は次のスニペットで終わったprint.foo()

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

に関連付けられているコードをインデントして表示しますx[["fun"]]


18

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

中置演算子

いくつかの基本中置演算子(例えば、のソースコードを参照するには%%%*%%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("%%")

主な答えは、ミラーを使用してさらに深く掘り下げる方法をカバーしています。


6
smciの回答を推奨getAnywhere。または、演算子の名前がわかっている場合は、バックティックを使用することもできます`%in%`
Joshua Ulrich

3
@JoshuaUlrichは、バッククォートを使用できることを知りませんでした!ありがとう。getAnywhereあなたの回答でも言及されていますが、infixへの特定の参照は、この回答への将来の参照に役立つと思います-このページを何度も読んだことがあり、そのような関数のコードを見つけるために、一方で-他の回答のフロー(どちらもgetAnywhere別の目的で使用している)のフローには適合しないと思いました。
MichaelChirico

10

Rには非常に便利な機能があります edit

new_optim <- edit(optim)

optimRで指定されたエディターを使用するソースコードを開き、options編集して変更した関数をに割り当てることができますnew_optim。コードを表示したり、コードをデバッグしたりするためにこの関数が非常に好きです。たとえば、いくつかのメッセージや変数を出力したり、さらに調査するためにグローバル変数に割り当てたりします(もちろんを使用できますdebug)。

ソースコードを表示したいだけで、面倒な長いソースコードをコンソールに出力したくない場合は、

invisible(edit(optim))

明らかに、これを使用してC / C ++またはFortranソースコードを表示することはできません。

ところで、editリストやマトリックスなどの他のオブジェクトを開くことができます。これにより、属性とともにデータ構造も表示されます。関数deを使用して、Excelのようなエディターを開き(GUIでサポートされている場合)、マトリックスまたはデータフレームを変更して新しいものを返すことができます。これはときどき便利ですが、通常の場合、特に行列が大きい場合は避けてください。


3
このアプローチは、関数を出力するのと同じ関数ソース(つまり、質問と同じ)を表示するだけです。それよりさらに深く/深くなることがこの質問についてです。
Brian Diggs、2014

2
@BrianDiggsはい、そうです。ジョシュアが完全な答えを出したので、私は質問に答えるつもりはありませんでした。私はトピックに関連する何かを追加しようとするだけで、興味深いものであり、知っておくと役立つ場合があります。
Eric

8

関数がC / C ++ / Fortranではなく純粋なRで書かれている限り、以下を使用できます。それ以外の場合、最善の方法はデバッグして「ジャンプ イン」を使用することです:

> functionBody(functionName)

2
これはと同じbodyです。identical(functionBody, body)ですTRUE
Joshua Ulrich

1
base::bodyそしてmethods::functionBody、彼らが破壊される可能性は低いですが。bodyオーバーライドすることもできます:rdocumentation.org/search
q=

7

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

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

新しいウィンドウが開き、ソースコードが表示されます。.Primitiveまたは.Cに達した場合は、別の方法が必要になります。申し訳ありません。


5

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


5

またprint.function()、S3ジェネリックであるを使用して、関数をコンソールに書き込むこともできます。


3
print.function()はS3 メソッドです。ジェネリックはprint()です。また、メソッドを直接呼び出すことは一般的にはお勧めできません。これは、汎用関数とメソッドディスパッチの目的全体を無効にします。
Joshua Ulrich
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.