我想查看功能的源代码以了解其工作原理。我知道可以在提示符下键入函数名称来打印该函数:

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


在这种情况下,UseMethod("t")是什么意思?我如何找到实际正在使用的源代码,例如:t(1:10)

和看到UseMethod时和看到standardGeneric时(如showMethods)之间有区别吗?

> 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


如何查找with.cbindts之类的函数?

在其他情况下,还有一些R代码,但大多数工作似乎都在其他地方完成。 br />
> 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")


我如何找出.makeNamesTs函数的作用?类似地,一些函数调用.Primitive.C.Call.Fortran.External。如何找到这些代码的源代码?

评论

另请参阅stackoverflow.com/q/1439348/134830

另请参见stackoverflow.com/questions/14035506/…

另请参见stackoverflow.com/questions/9385411/…

#1 楼

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.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()函数可以为您获取软件包的来源。这将下载Matrix软件包的源版本,并将相应的.tar.gz文件保存在当前目录中。可以在未压缩和解压缩文件的src目录中找到已编译函数的源代码。可以在R外部或使用R函数在untar()内完成解压缩和解压缩步骤。可以将下载和扩展步骤组合为一个调用(请注意,每次只能以这种方式下载和解压缩一个软件包):

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


另外,如果程序包开发是公开托管的(例如,通过GitHub,R-Forge或RForge.net),则您可能可以在线浏览源代码。

基本程序包中的已编译代码

某些程序包被视为“基本”程序包。这些软件包随R一起提供,其版本已锁定为R的版本。示例包括basecompilerstatsutils。因此,如上所述,它们不能作为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条目”名称。

评论


如果使用RStudio,则按F2键将尝试拉出文本光标所在功能的源。

–阿里·弗里德曼(Ari B. Friedman)
13-10-26在19:37

@Ari B. Friedman对不起,这个问题很抱歉。 RStudio是否还会为函数或仅为用R编写的函数提取C源代码?谢谢

–晴天
2014年2月24日15:12

@Samir我相信这只是R源。

–阿里·弗里德曼(Ari B. Friedman)
2014年2月25日下午0:55

@ AriB.Friedman-谢谢Ari,这很方便。就我而言,我仍然需要答案中显示的知识(小数位数,即S3-我得到UseMethod(“ scale”),然后使用getAnywhere(scale.default))。但是普通功能可以正常工作。

– Tomasz Gandor
17年5月12日在8:36

模仿是最恭维的奉承形式,我认为这个答案/维基是第一位的:)在此之前,rfaqs.com / source-code-of-r-method

– JimLohse
18 Mar 27 '18 at 14:42

#2 楼

除了关于此问题及其重复项的其他答案外,这也是一种获取软件包功能源代码的好方法,而无需知道其位于哪个软件包中。
例如假设我们要randomForest::rfcv()的源代码:
要在弹出窗口中查看/编辑它:
edit(getAnywhere('rfcv'), file='source_rfcv.r')

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

请注意,edit()打开文本编辑器(用户选择),而
/> View()调用电子表格样式的数据查看器。


View()非常适合浏览(多列)数据,但通常对于除玩具长度以外的任何代码都非常糟糕。
因此,当只想查看代码时,edit()确实比IMO更好,因为View()可以折叠/隐藏/虚拟所有arg-parsing / checking / default / error-message逻辑,最多可占用70% R函数,然后转到该函数实际在其中执行某些操作的部分!返回值是什么类型的对象,是否以及如何递归等。

要重定向到一个单独的文件(因此您可以在您喜欢的IDE /编辑器中调出代码,或使用grep / etc处理它):
capture.output(getAnywhere('rfcv'), file='source_rfcv.r')


评论


诚然,对于应该被称为findOnSearchPath或类似名称的东西,getAnywhere是另一个古怪的R名称选择。

–smci
15年8月21日在19:48

我会回答这个问题,因为它使我接近了想要的结果。在RStudio中,我真正想要的是View(foo);。 foo是已经加载的包中的函数。

– Sigfried
19年2月28日在11:35

@Sigfried:edit()打开一个文本编辑器(由用户选择),而View()打开一个Excel类型的电子表格查看器来存储数据,后者对于浏览(多列)数据很有用,但是通常对任何代码都很糟糕除了玩具长度。例如,正如我所暗示的那样,浏览功能时,我通常要做的第一件事就是跳过/折叠/虚拟所有的arg解析和默认操作逻辑,以了解该功能的实际作用。

–smci
19 Mar 4 '19在5:22



@Sigfried:已更新,以包含所有这些备注/提示。

–smci
7月28日21:19

#3 楼

使用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()即可实现相同功能

评论


与接受的答案相比,此方法的缺点是您需要一个工作函数调用(指定了所有必需的参数,可以接受);而且,除了最初的代码块外,您还可以在运行时获得每个块。这对于调试非常有用,但对于仅获取源代码而言并不是最佳选择。

–布赖恩·迪格斯(Brian Diggs)
2014年8月12日15:33

是的,它不是最佳的。但是,如果您很聪明,则可以快速而轻松地获取源代码,尤其是内置函数。

–塞尔瓦
14年8月13日在16:21

我也建议在这种情况下使用debugonce而不是debug。

–约书亚·乌尔里希(Joshua Ulrich)
14年8月18日在20:20

#4 楼

对于非基本函数,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")。列表成员之一(名为“ fun”)是一个函数,我希望print.foo()显示缩进的函数源代码。因此,我在print.foo()中得到了以下代码片段:

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


缩进并显示与x[["fun"]]相关的代码。

#5 楼

没看到它如何适应主要答案的流程,但它让我感到沮丧,所以我在这里添加了它:
中缀运算符
查看一些基本中缀运算符的源代码(例如,%%%*%%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("%%")

主要答案涵盖了如何使用镜子进行更深的挖掘。

评论


smci的答案推荐getAnywhere。或者,如果您已经知道运算符的名称,则可以使用反引号:%in%。

–约书亚·乌尔里希(Joshua Ulrich)
2015年1月1日于20:32



@JoshuaUlrich不知道您可以使用反引号!谢谢。您的答案中也提到了getAnywhere,但我认为对infix的特定引用对于以后对该答案的引用很有用-我已经阅读了很多次此页面,并且仍然试图为此类函数查找代码仍然有些困惑一阵子-我认为它不适合其他任何答案(它们都使用getAnywhere来实现其他目的)。

–MichaelChirico
2015年12月1日于20:37

#6 楼

R edit中有一​​个非常方便的功能

new_optim <- edit(optim)


它将使用R的optim中指定的编辑器打开options的源代码,然后您可以对其进行编辑和分配对new_optim的修改功能。我非常喜欢此功能来查看代码或调试代码,例如,打印一些消息或变量,甚至将它们分配给全局变量以进行进一步研究(当然,您可以使用debug)。

如果您只想查看源代码,而又不想在控制台上打印烦人的长源代码,则可以使用

invisible(edit(optim))


很显然,该功能无法使用要查看C / C ++或Fortran源代码。

BTW,edit可以打开其他对象,如列表,矩阵等,然后显示具有属性的数据结构。函数de可用于打开一个excel之类的编辑器(如果GUI支持),以修改矩阵或数据框并返回新的。有时候这很方便,但是在通常情况下应该避免使用,尤其是当矩阵很大时。

评论


这种方法只调出与打印功能所提供的功能相同的源(即与问题中的功能相同)。比这个问题更进一步/更深入。

–布赖恩·迪格斯(Brian Diggs)
2014年12月5日下午6:17

@BrianDiggs是的,您是对的。我并不是要回答这个问题,因为约书亚给出了相当完整的答案。我只是尝试添加与该主题相关的内容,这些有趣的内容可能对您有所帮助。

–埃里克
2014年12月5日在16:23

对不起,我已经在7个月前发布了此帖子。尽管使用了invisible(edit(...))是一个很好的技巧,但也有注释“在C / C ++或Fortran上不起作用”。

–smci
7月28日21:20



#7 楼

只要该函数是用纯R而不是C / C ++ / Fortran编写的,则可以使用以下代码。否则,最好的方法是调试并使用“跳入”:

> functionBody(functionName)


评论


这与身体相同。 same(functionBody,body)为TRUE。

–约书亚·乌尔里希(Joshua Ulrich)
17年1月24日在18:26

base :: body和methods :: functionBody,尽管它们不太可能被删除。正文也可以被覆盖:rdocumentation.org/search?q=body

– Moody_Mudskipper
17年10月10日在22:03

#8 楼

在RStudio中,(至少)有3种方法:在光标位于任何功能上时,按F2键。
按住Ctrl或Command的同时单击函数名称

View(函数名)(如上所述)

将打开一个新窗格,其中带有源代码。如果您达到.Primitive或.C,则需要另一种方法,对不起。

#9 楼

您也可以尝试使用S3通用的print.function()将功能写入控制台。

评论


print.function()是一种S3方法。泛型是print()。直接调用方法通常不是一个好主意。这破坏了泛型函数和方法分派的全部目的。

–约书亚·乌尔里希(Joshua Ulrich)
17年12月27日在21:48

#10 楼

View(function_name)-例如View(mean)确保使用大写[V]。只读代码将在编辑器中打开。