[r] 함수의 소스 코드를 어떻게 볼 수 있습니까?

작동 방식을 확인하는 함수의 소스 코드를보고 싶습니다. 프롬프트에서 이름을 입력하여 함수를 인쇄 할 수 있다는 것을 알고 있습니다.

> 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. 해당 소스 코드를 어떻게 찾을 수 있습니까?



답변

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로부터 안 export 기능입니다 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:::C_optimhess호출 된 컴파일 된 함수에 대한 정보를 볼 수 있습니다 .

패키지의 컴파일 된 코드

패키지에서 컴파일 된 코드를 보려면 패키지 소스를 다운로드 / 포장 풀어야합니다. 설치된 바이너리가 충분하지 않습니다. 패키지의 소스 코드는 패키지가 원래 설치된 동일한 CRAN (또는 CRAN 호환) 저장소에서 사용 가능합니다. 이 download.packages()함수는 패키지 소스를 얻을 수 있습니다.

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

그러면 Matrix 패키지의 소스 버전이 다운로드되고 해당 .tar.gz파일이 현재 디렉토리에 저장 됩니다. 컴파일 된 함수의 소스 코드 src는 압축되지 않은 파일과 압축 해제 된 파일 의 디렉토리 에서 찾을 수 있습니다 . 압축 해제 및 untaring 단계는 외부 R에서 또는 기능을 R사용하여 수행 할 수 있습니다 untar(). 다운로드 및 확장 단계를 단일 호출로 결합 할 수 있습니다 (한 번에 하나의 패키지 만이 방식으로 다운로드 및 포장 풀기 가능).

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

또는 패키지 개발이 공개적으로 호스팅되는 경우 (예 : GitHub , R-Forge 또는 RForge.net ) 소스 코드를 온라인에서 찾아 볼 수 있습니다.

기본 패키지의 컴파일 된 코드

특정 패키지는 “기본”패키지로 간주됩니다. 이 패키지는 R와 함께 제공과 버전은 다음과 같습니다 R. 예 버전에 잠겨 base, compiler, stats,와 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/*.


답변

이 질문과 그 중복에 대한 다른 답변 외에도 패키지 기능에 대한 소스 코드를 얻을 필요없이 패키지 함수의 소스 코드를 얻는 좋은 방법이 있습니다 randomForest::rfcv().

팝업 창에서 보거나 편집 하려면

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

하려면 별도의 파일로 리디렉션 :

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


답변

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 ()를 사용하지 않고도 동일한 결과를 얻습니다.


답변

기본이 아닌 함수의 경우 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, where class(x) = "foo")를 작성했습니다. “fun”이라는 목록 멤버 중 하나가 함수였으며 print.foo()들여 쓰기 된 함수 소스 코드를 표시 하려고 했습니다. 그래서 나는 다음 스 니펫으로 끝났습니다 print.foo().

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

에 연결된 코드를 들여 쓰고 표시합니다 x[["fun"]].


답변

이것이 주요 답변의 흐름에 어떻게 적합한 지 보지 못했지만 잠시 동안 저를 비틀어 여기에 추가하고 있습니다.

대입 연산자

일부 기본 중위 사업자 (예를 들어,의 소스 코드를 확인하려면 %%, %*%, %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에는 매우 편리한 기능이 있습니다 edit

new_optim <- edit(optim)

그것은 소스 코드를 열 것입니다 optimR에 지정된 편집기 사용하여options 다음 편집하고 수정 된 기능을에 할당 할 수 있습니다 new_optim. 이 함수는 코드를 보거나 코드를 디버깅하는 데 매우 유용 debug합니다. 예를 들어 일부 메시지 나 변수를 인쇄하거나 추가 조사를 위해 전역 변수에 할당 할 수도 있습니다 (물론 사용할 수 있습니다 ).

소스 코드 만보고 콘솔에 성가신 긴 소스 코드를 인쇄하지 않으려면

invisible(edit(optim))

분명히 이것은 C / C ++ 또는 Fortran 소스 코드를 보는 데 사용할 수 없습니다.

BTW edit는 목록, 행렬 등과 같은 다른 객체를 열 수 있으며 속성이있는 데이터 구조를 보여줍니다. 이 함수 de는 편집기와 같은 엑셀 (GUI가 지원하는 경우)을 열어 매트릭스 또는 데이터 프레임을 수정하고 새 프레임을 반환하는 데 사용할 수 있습니다. 이것은 때로는 편리하지만 일반적인 경우, 특히 행렬이 큰 경우에는 피해야합니다.


답변

함수가 C / C ++ / Fortran이 아닌 순수한 R로 작성되는 한 다음을 사용할 수 있습니다. 그렇지 않으면 가장 좋은 방법은 디버깅 하고 ” jump into “를 사용하는 것입니다.

> functionBody(functionName)