Jak mogę wyświetlić kod źródłowy funkcji?

Chcę spojrzeć na kod źródłowy funkcji, aby zobaczyć, jak to działa. Wiem, że mogę wydrukować funkcję wpisując jej nazwę w wierszu polecenia:

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

W tym przypadku, co oznacza UseMethod("t")? Jak znaleźć kod źródłowy, który jest faktycznie używany przez, na przykład: t(1:10)?

Czy jest różnica między Kiedy widzę UseMethod a kiedy widzę standardGeneric i showMethods, jak z 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.

W innych przypadkach widzę, że funkcje R są wywoływane, ale nie mogę znaleźć źródła kod dla tych funkcji.

> 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

Jak znaleźć funkcje takie jak .cbindts i .makeNamesTs?

W jeszcze innych przypadkach, jest trochę kodu R, ale większość pracy wydaje się być wykonywana gdzie indziej.

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

Jak sprawdzić, co robi funkcja .Primitive? Podobnie niektóre funkcje wywołują .C, .Call, .Fortran, .External, lub .Internal. Jak mogę znaleźć dla nich kod źródłowy?

Author: MichaelChirico, 2013-10-07

9 answers

UseMethod("t") mówi, że t() jest (S3) funkcją ogólną, która ma metody dla różnych klas obiektów.

System wysyłki metody S3

Dla klas S3, możesz użyć funkcji methods, aby wyświetlić listę metod dla konkretnej ogólnej funkcji lub klasy.

> 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

"funkcje niewidoczne są oznaczone gwiazdką" oznacza, że funkcja nie jest eksportowana z przestrzeni nazw pakietu. Nadal możesz wyświetlić jego kod źródłowy za pomocą funkcji ::: (tj. stats:::t.ts), lub za pomocą getAnywhere(). getAnywhere() jest przydatne, ponieważ nie musisz wiedzieć, z którego pakietu pochodzi ta funkcja.

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

System wysyłki metody S4

System S4 jest nowszym systemem wysyłania metod i jest alternatywą dla systemu S3. Oto przykład funkcji 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.

Wyjście oferuje już wiele informacji. standardGeneric jest wskaźnikiem funkcji S4. Metoda, aby zobaczyć zdefiniowane metody S4, jest oferowana pomocnie:

> showMethods(chol2inv)
Function: chol2inv (package base)
x="ANY"
x="CHMfactor"
x="denseMatrix"
x="diagonalMatrix"
x="dtrMatrix"
x="sparseMatrix"

getMethod może być używane, aby zobaczyć kod źródłowy jednej z metod:

> getMethod("chol2inv", "diagonalMatrix")
Method Definition:

function (x, ...) 
{
    chk.s(...)
    tcrossprod(solve(x))
}
<bytecode: 0x000000000ea2cc70>
<environment: namespace:Matrix>

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"
Istnieją również metody o bardziej złożonych podpisach dla każdej z metod, na przykład
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"

Aby zobaczyć kod źródłowy jednej z tych metod, należy podać cały podpis, np.

getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") )

Nie wystarczy podać częściowego podpisu

getMethod("extract",signature="SpatialPolygons")
#Error in getMethod("extract", signature = "SpatialPolygons") : 
#  No method found for function "extract" and signature SpatialPolygons

Funkcje, które wywołują funkcje niezerowe

W przypadku ts.union, .cbindts i .makeNamesTs są funkcjami z stats przestrzeń nazw. Kod źródłowy funkcji nieprzetworzonych można wyświetlić za pomocą operatora ::: lub 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>

Funkcje wywołujące skompilowany kod

Zauważ, że "skompilowany" nie odnosi się do skompilowanego bajtowo kodu R utworzonego przez pakiet kompilatora. Linia <bytecode: 0x294e410> na powyższym wyjściu wskazuje, że funkcja jest skompilowana bajtowo i nadal można wyświetlić źródło z wiersza poleceń R.

Funkcje wywołujące .C, .Call, .Fortran, .External, .Internal, lub .Primitive wywołują punkty wejścia w skompilowanym kodzie, więc będziesz musiał spojrzeć na źródła skompilowanego kodu, jeśli chcesz w pełni zrozumieć funkcję. to Lustro GitHub kodu źródłowego R jest przyzwoitym miejscem do rozpoczęcia. Funkcja pryr::show_c_source może być użytecznym narzędziem, ponieważ przeniesie Cię bezpośrednio do strony GitHub dla wywołań .Internal i .Primitive. Opakowania mogą używać .C, .Call, .Fortran, i .External; ale nie .Internal czy .Primitive, ponieważ są one używane do wywoływania funkcji wbudowanych w R Tłumacz.

Wywołania niektórych z powyższych funkcji mogą używać obiektu zamiast ciągu znaków do odwoływania się do skompilowanej funkcji. W takich przypadkach obiekt należy do klasy "NativeSymbolInfo", "RegisteredNativeSymbol", lub "NativeSymbol"; a wydrukowanie obiektu daje użyteczne informacje. Na przykład, optim wywołuje .External2(C_optimhess, res$par, fn1, gr1, con) (zauważ, że jest to C_optimhess, a nie "C_optimhess"). optim Znajduje się w pakiecie stats, więc możesz wpisać stats:::C_optimhess, aby zobaczyć informacje o wywołanej funkcji.

Skompilowany kod w pakiet

Jeśli chcesz wyświetlić skompilowany kod w pakiecie, musisz pobrać / rozpakować źródło pakietu. Zainstalowane pliki binarne nie są wystarczające. Kod źródłowy pakietu jest dostępny z tego samego repozytorium Cran (lub kompatybilnego z CRAN), z którego pakiet został pierwotnie zainstalowany. Funkcja download.packages() może pobrać źródło pakietu dla Ciebie.

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

Spowoduje to pobranie wersji źródłowej pakietu Matrix i zapisanie odpowiedniego pliku .tar.gz w bieżącym katalog. Kod źródłowy skompilowanych funkcji można znaleźć w katalogu src nieskompresowanego i nie udostępnionego pliku. Krok rozpakowywania i rozpakowywania można wykonać poza R, lub z wewnątrz {[54] } za pomocą funkcji untar(). Możliwe jest połączenie kroku download I expansion w jedno wywołanie (należy pamiętać, że tylko jeden pakiet na raz może być pobrany i rozpakowany w ten sposób): {]}

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

Alternatywnie, jeśli rozwój pakietu jest hostowany publicznie (np. poprzez GitHub, R-Forge , or RForge.net ), prawdopodobnie możesz przeglądać kod źródłowy online.

Skompilowany kod w pakiecie bazowym

Niektóre pakiety są uważane za pakiety "podstawowe". Pakiety te są dostarczane z R, a ich wersja jest zablokowana do wersji R. przykłady obejmują base, compiler, stats, i utils. W związku z tym nie są one dostępne jako oddzielne pakiety do pobrania na CRAN, jak opisano powyżej. Są raczej częścią drzewa źródłowego R w poszczególne katalogi pakietów pod /src/library/. Jak uzyskać dostęp do źródła R opisano w następnej sekcji.

Skompilowany kod wbudowany w interpreter R

Jeśli chcesz zobaczyć kod wbudowany w interpreter r, musisz pobrać / rozpakować źródła R; lub możesz przeglądać źródła online za pośrednictwem repozytorium R Subversion lub Winstona Changa na github mirror.

Uwe Ligges ' s r news article (PDF) (s. 43) is a good general odniesienie do sposobu wyświetlania kodu źródłowego funkcji .Internal i .Primitive. Podstawowe kroki to najpierw poszukać nazwy funkcji w src/main/names.c, a następnie wyszukać nazwę "C-entry" w plikach w src/main/*.

 408
Author: Joshua Ulrich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:26

Oprócz innych odpowiedzi na to pytanie i jego duplikatów, oto dobry sposób na uzyskanie kodu źródłowego funkcji pakietu bez konieczności wiedzieć, w którym pakiecie się znajduje. np. jeśli chcemy mieć źródło dla randomForest::rfcv():

Do Wyświetl/edytuj w wyskakującym oknie:

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

Do przekierowanie do osobnego pliku :

capture.output(getAnywhere('rfcv'), file='source_rfcv.r')
 79
Author: smci,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-29 18:58:39

Zostanie ujawniona podczas debugowania za pomocą funkcji debug (). Załóżmy, że chcesz zobaczyć kod źródłowy w funkcji transpozycja t (). Samo wpisanie "t" nie ujawnia zbyt wiele.

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

Ale, używając ' debug (functionName)', ujawnia kod bazowy, bez wewnętrznych.

> 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() osiąga to samo bez konieczności używania undebug ()

 21
Author: Selva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-20 03:33:34

Nie widziałem jak to wpasowuje się w nurt głównej odpowiedzi, ale przez chwilę mnie to zaskoczyło, więc dodaję to tutaj:

Operatory Infiksowe

Aby zobaczyć kod źródłowy niektórych bazowych operatorów infiksowych (np., %%, %*%, %in%), Użyj getAnywhere, np.:

getAnywhere("%%")
# A single object matching ‘%%’ was found
# It was found in the following places
#   package:base
#   namespace:base
#  with value
#
# function (e1, e2)  .Primitive("%%")

Główna odpowiedź obejmuje, Jak następnie używać luster do kopania głębiej.

 13
Author: MichaelChirico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-29 19:30:53

Dla funkcji nie-prymitywnych baza r zawiera funkcję o nazwie body(), która zwraca ciało funkcji. Na przykład źródło funkcji print.Date() można wyświetlić:

body(print.Date)

Wyprodukuje to:

{
    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)
}

Jeśli pracujesz w skrypcie i chcesz, aby kod funkcji był wektorem znaków, możesz go uzyskać.

capture.output(print(body(print.Date)))

Dostaniesz:

[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] "}"     
Po co miałbym to robić? Tworzyłem własny obiekt S3 (x, gdzie class(x) = "foo") na podstawie listy. Jeden z listy członków (o nazwie "fun") była funkcja i chciałem print.foo(), aby wyświetlić kod źródłowy funkcji, wcięty. Więc skończyłem z następującym fragmentem w print.foo():
sourceVector = capture.output(print(body(x[["fun"]])))
cat(paste0("      ", sourceVector, "\n"))

, który wcina i wyświetla kod powiązany z x[["fun"]].

 11
Author: Geoffrey Poole,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-09 23:34:04

Istnieje bardzo przydatna funkcja W R edit

new_optim <- edit(optim)

Otworzy kod źródłowy optim używając edytora określonego W R options, a następnie możesz go edytować i przypisać zmodyfikowaną funkcję do new_optim. Bardzo podoba mi się Ta funkcja, aby wyświetlić kod lub debugować kod, np. wydrukować niektóre wiadomości lub zmienne, a nawet przypisać je do globalnych zmiennych do dalszego badania(oczywiście możesz użyć debug).

Jeśli chcesz tylko wyświetlić kod źródłowy i nie chcesz denerwujących długi kod źródłowy wydrukowany na konsoli, możesz użyć

invisible(edit(optim))

Oczywiście nie można tego użyć do wyświetlenia kodu źródłowego C/C++ lub Fortran.

BTW, {[2] } może otwierać inne obiekty, takie jak lista, macierz itp., które następnie pokazują strukturę danych wraz z atrybutami. Funkcja de może być użyta do otwarcia edytora Excela (jeśli obsługuje go GUI), aby zmodyfikować macierz lub ramkę danych i zwrócić nową. Jest to przydatne czasami, ale należy unikać w zwykłym przypadku, zwłaszcza, gdy macierz jest duży.

 6
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-04 23:39:33

Tak długo, jak funkcja jest napisana w czystym R, a nie w C / C++ / Fortran, można użyć następującego polecenia. W przeciwnym razie najlepszym sposobem jest debugowanie i użycie " jump do":

> functionBody(functionName)
 3
Author: MCH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-08 10:56:34

View([function_name]) - np. View(mean) Upewnij się, że używasz wielkich liter [V]. Kod tylko do odczytu zostanie otwarty w edytorze.

 2
Author: Koo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-11 02:45:22

Możesz również spróbować użyć print.function(), która jest generyczna dla S3, aby uzyskać funkcję write w konsoli.

 2
Author: strboul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-26 11:45:54