Я хочу посмотреть исходный код функции, чтобы увидеть, как она работает. Я знаю, что могу напечатать функцию, набрав ее имя в строке:
> 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
. Как я могу найти исходный код для них?
UseMethod("t")
сообщает вам, что t()
является (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 представляет собой более новую систему диспетчеризации методов и является альтернативой системе 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 репозиторий Subversion или Winston Chang github зеркало.
Uwe Ligges новостная статья R (PDF) (стр. 43) является хорошей общей ссылкой о том, как просмотреть исходный код для .Internal
и .Primitive
. Основные шаги - сначала искать имя функции в src/main/names.c
, а затем искать имя "C-entry" в файлах в src/main/*
.
RStudio
, он попытается получить источник для функции, над которой находится текстовый курсор, если вы нажмете клавишу F2
.
В дополнение к другим ответам на этот вопрос и его дубликатам, здесь хороший способ получить исходный код для функции пакета без необходимости знать, в какой пакет он находится.
например если нам нужен источник для 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)
EDIT: debugonce() выполняет то же самое без использования undebug()
Не видел, как это вписывается в поток основного ответа, но меня это застопорило какое-то время, поэтому я добавляю его здесь:
Чтобы увидеть исходный код некоторых базовых инфиксных операторов (например, %%
, %*%
, %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("%%")
В главном ответе описывается, как затем использовать зеркала, чтобы копать глубже.
getAnywhere
рекомендовал getAnywhere
. Или вы можете просто использовать обратные пометки, если вы уже знаете имя оператора: `%in%`
.
getAnywhere
упоминается в вашем ответе, но я думаю, что конкретная ссылка на infix полезна для будущей ссылки на этот ответ - я много раз читал эту страницу и все еще был немного озадачен, пытаясь найти код для таких функций для какое-то время - и я не думал, что это вписывается в поток любого другого ответа (оба используют getAnywhere
для другой цели).
Для непримитивных функций база 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"]]
.
В R edit
new_optim <- edit(optim)
Он откроет исходный код optim
, используя редактор, указанный в R options
, а затем вы можете отредактировать его и назначить измененной функции new_optim
. Мне очень нравится эта функция, чтобы просматривать код или отлаживать код, например, печатать некоторые сообщения или переменные или даже назначать их глобальным переменным для дальнейшего исследования (конечно, вы можете использовать debug
).
Если вы просто хотите просмотреть исходный код и не хотите, чтобы на консоль был напечатан раздражающий длинный исходный код, вы можете использовать
invisible(edit(optim))
Ясно, что это невозможно использовать для просмотра исходного кода C/С++ или Fortran.
BTW, edit
могут открывать другие объекты, такие как список, матрица и т.д., которые также показывают структуру данных с атрибутами. Функция de
может быть использована для открытия редактора Excel (если он поддерживает GUI) для изменения матрицы или кадра данных и возврата нового. Иногда это удобно, но его следует избегать в обычном случае, особенно когда вы крупны.
Пока функция написана в чистом R не C/С++/Fortran, можно использовать следующее. В противном случае наилучшим способом является отладка и использование " jump в":
> functionBody(functionName)
body
. identical(functionBody, body)
TRUE
.
base::body
и methods::functionBody
, хотя они непривычны для отсоединения. body
может быть переопределено: rdocumentation.org/search?q=body
Вы также можете попробовать использовать print.function()
, который является S3 generic, чтобы функция записывалась в консоль.
print.function()
- это метод S3. Универсальным является print()
. И вообще не стоит вызывать методы напрямую. Это наносит ущерб всей цели универсальных функций и методов отправки.
View([function_name])
- например. View(mean)
Обязательно используйте прописные буквы [V]. Код только для чтения откроется в редакторе.