xmu - the r project for statistical computing http www r project org




我如何查看函數的源代碼? (6)

我想看看函數的源代碼,看看它是如何工作的。 我知道我可以通過在提示符處輸入它的名字來打印一個函數:

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

在這種情況下, UseMethod("t")是什麼意思? 我如何找到實際使用的源代碼,例如: t(1:10)

在其他情況下,我可以看到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.Fortran.Internal 。 我如何找到這些源代碼?


R edit有一個非常方便的功能

new_optim <- edit(optim)

它將使用R options指定的編輯器打開optim的源代碼,然後您可以對其進行編輯並將修改後的函數分配給new_optim 。 我非常喜歡這個函數來查看代碼或調試代碼,例如打印一些消息或變量,甚至將它們分配給全局變量以供進一步調查(當然,您可以使用debug )。

如果您只想查看源代碼並且不希望在控制台上打印煩人的長源代碼,則可以使用

invisible(edit(optim))

顯然,這不能用於查看C / C ++或Fortran源代碼。

順便說一句, edit可以打開列表,矩陣等其他對象,然後顯示具有屬性的數據結構。 函數de可以用來打開一個類似於Excel的編輯器(如果GUI支持它)來修改矩陣或數據框並返回新的。 這有時很方便,但通常情況下應該避免,特別是當矩陣很大時。


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"

要查看這些方法之一的源代碼,必須提供整個簽名,例如

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.Call.Fortran.Internal.Primitive正在調用編譯代碼中的入口點,因此如果您想完全理解該函數,則必須查看已編譯代碼的來源。 This R源代碼的GitHub鏡像是一個體面的開始。 函數pryr::show_c_source可以是一個有用的工具,因為它可以直接將您.Primitive.Internal.Primitive調用的GitHub頁面。 包可能使用.C.Call.Fortran.Fortran ; 但不是.Internal.Primitive ,因為它們用於調用內置到R解釋器中的函數。

調用上述某些函數可能會使用對象而不是字符串來引用編譯後的函數。 在這些情況下,該對"NativeSymbolInfo""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之外完成,也可以在R之內使用untar()函數完成。 可以將下載和擴展步驟合併為一次調用(請注意,一次只能下載和解包一個包):

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

或者,如果軟件包開發是公開託管的(例如,通過GitHubR-ForgeRForge.net ),則可以在線瀏覽源代碼。

在基本軟件包中編譯代碼

某些軟件包被視為“基礎”軟件包。 這些軟件包隨附R,並且它們的版本被鎖定到R的版本。示例包括basecompilerstatsutils 。 因此,如上所述,它們在CRAN上不能作為單獨的可下載軟件包提供。 相反,它們是/src/library/下獨立包目錄中R源樹的一部分。 下一節將介紹如何訪問R源。

編譯內置在R解釋器中的代碼

如果您想查看R解釋器的內置代碼,您需要下載/解壓縮R源代碼; 或者您可以通過R Subversion版本庫Winston Chang的github鏡像在線查看源代碼。

Uwe Ligges的R新聞文章(PDF) (第43頁)是如何查看.Internal.Primitive函數源代碼的很好的一般參考。 基本步驟是首先在src/main/names.c查找函數名稱,然後在src/main/*文件中搜索“C-entry”名稱。


只要函數是用純R而不是C / C ++ / Fortran編寫的,就可以使用以下內容。 否則,最好的方法是調試並使用“ 跳入 ”:

> functionBody(functionName)

它在使用debug()函數進行調試時顯示。 假設你想在t()轉置函數中看到底層代碼。 只要輸入't',不會顯示太多。

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

但是,使用'調試(函數名)',它揭示了底層代碼,沒有內部。

> 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()


您也可以嘗試使用print.function()通用S3)來獲取控制台中的函數寫入。


沒有看到這是如何適應主流答案的流程,但它困難了一段時間,所以我在這裡添加它:

中綴操作員

要查看一些基礎中綴運算符的源代碼(例如, %%%*%%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("%%")

主要答案涵蓋瞭如何使用鏡子深入挖掘。





r-faq