Подтвердить что ты не робот

Как просмотреть исходный код для функции?

Я хочу посмотреть исходный код функции, чтобы увидеть, как она работает. Я знаю, что могу напечатать функцию, набрав ее имя в строке:

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

В этом случае, что означает UseMethod("t")? Как найти исходный код, который фактически используется, например: t(1:10)?

Есть ли разница между тем, когда я вижу UseMethod и когда я вижу standardGeneric и showMethods, как с 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 функция .Primitive? Кроме того, некоторые функции вызывают .C, .Call, .Fortran, .External или .Internal. Как я могу найти исходный код для них?

4b9b3361

Ответ 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, вызывают точки входа в скомпилированном коде, поэтому вам придется искать источники скомпилированного кода если вы хотите полностью понять эту функцию. Это Зеркало GitHub исходного кода R - достойное место для запуска. Функция 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 несжатого и неустановленного файла. Разомкнутый и необратимый шаг можно выполнить вне 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) (стр. 43) является хорошей общей ссылкой о том, как просмотреть исходный код для .Internal и .Primitive. Основные шаги - сначала искать имя функции в src/main/names.c, а затем искать имя "C-entry" в файлах в src/main/*.

Ответ 2

В дополнение к другим ответам на этот вопрос и его дубликатам, здесь хороший способ получить исходный код для функции пакета без необходимости знать, в какой пакет он находится. например если нам нужен источник для randomForest::rfcv():

Чтобы просмотреть/отредактировать во всплывающем окне:

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

В перенаправление на отдельный файл:

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

Ответ 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)

EDIT: debugonce() выполняет то же самое без использования undebug()

Ответ 4

Не видел, как это вписывается в поток основного ответа, но меня это застопорило какое-то время, поэтому я добавляю его здесь:

Операторы Infix

Чтобы увидеть исходный код некоторых базовых инфиксных операторов (например, %%, %*%, %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("%%")

В главном ответе описывается, как затем использовать зеркала, чтобы копать глубже.

Ответ 5

Для непримитивных функций база R включает в себя функцию с именем 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)
}

Если вы работаете в script и хотите, чтобы код функции был символьным символом, вы можете получить его.

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"]].

Ответ 6

В R edit

есть очень удобная функция,
new_optim <- edit(optim)

Он откроет исходный код optim, используя редактор, указанный в R options, а затем вы можете отредактировать его и назначить измененной функции new_optim. Мне очень нравится эта функция, чтобы просматривать код или отлаживать код, например, печатать некоторые сообщения или переменные или даже назначать их глобальным переменным для дальнейшего исследования (конечно, вы можете использовать debug).

Если вы просто хотите просмотреть исходный код и не хотите, чтобы на консоль был напечатан раздражающий длинный исходный код, вы можете использовать

invisible(edit(optim))

Ясно, что это невозможно использовать для просмотра исходного кода C/С++ или Fortran.

BTW, edit могут открывать другие объекты, такие как список, матрица и т.д., которые также показывают структуру данных с атрибутами. Функция de может быть использована для открытия редактора Excel (если он поддерживает GUI) для изменения матрицы или кадра данных и возврата нового. Иногда это удобно, но его следует избегать в обычном случае, особенно когда вы крупны.

Ответ 7

Пока функция написана в чистом R не C/С++/Fortran, можно использовать следующее. В противном случае наилучшим способом является отладка и использование " jump в":

> functionBody(functionName)

Ответ 8

Вы также можете попробовать использовать print.function(), который является S3 generic, чтобы функция записывалась в консоль.

Ответ 9

View([function_name]) - например. View(mean) Обязательно используйте прописные буквы [V]. Код только для чтения откроется в редакторе.

Ответ 10

В RStudio есть (как минимум) 3 способа:

  1. Нажмите клавишу F2, когда курсор находится на любой функции.
  2. Нажмите на название функции, удерживая Ctrl или Command
  3. View (имя_функции) (как указано выше)

Откроется новая панель с исходным кодом. Если вы достигнете .Primitive или .C, вам понадобится другой метод, извините.