una - visualizzare sorgente pagina iphone




Come posso visualizzare il codice sorgente di una funzione? (6)

C'è una funzione molto utile in R edit

new_optim <- edit(optim)

Si aprirà il codice sorgente di optim usando l'editor specificato nelle options di R, quindi potrai modificarlo e assegnare la funzione modificata a new_optim . Mi piace molto questa funzione per visualizzare il codice o per eseguire il debug del codice, ad esempio, stampare alcuni messaggi o variabili o persino assegnarli a variabili globali per ulteriori indagini (ovviamente è possibile utilizzare il debug ).

Se vuoi solo visualizzare il codice sorgente e non vuoi che il codice sorgente lungo e fastidioso stampato sulla tua console, è possibile utilizzare

invisible(edit(optim))

Chiaramente, questo non può essere usato per visualizzare il codice sorgente di C / C ++ o Fortran.

A proposito, la edit può aprire altri oggetti come lista, matrice, ecc. Che poi mostra anche la struttura dei dati con gli attributi. La funzione de può essere utilizzata per aprire un editor come Excel (se la GUI lo supporta) per modificare la matrice o il frame di dati e restituire quello nuovo. Questo è utile a volte, ma dovrebbe essere evitato nel solito caso, soprattutto quando la matrice è grande.

Voglio vedere il codice sorgente di una funzione per vedere come funziona. So che posso stampare una funzione digitandone il nome al prompt:

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

In questo caso, cosa significa UseMethod("t") ? Come trovo il codice sorgente effettivamente utilizzato, ad esempio: t(1:10) ?

C'è una differenza tra quando vedo UseMethod e quando vedo standardGeneric e showMethods , come 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.

In altri casi, posso vedere che vengono chiamate le funzioni R, ma non riesco a trovare il codice sorgente per tali funzioni.

> 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

Come trovo funzioni come .cbindts e .makeNamesTs ?

In altri casi ancora, c'è un po 'di codice R, ma la maggior parte del lavoro sembra essere fatta da qualche altra parte.

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

Come faccio a sapere che cosa fa la funzione .Primitive ? Allo stesso modo, alcune funzioni chiamano .C , .Call , .Fortran , .External o .Internal . Come posso trovare il codice sorgente per quelli?


Finché la funzione è scritta in puro R non C / C ++ / Fortran, si può usare quanto segue. Altrimenti il ​​modo migliore è il debugging e l'utilizzo di " jump into ":

> functionBody(functionName)

Oltre alle altre risposte a questa domanda e ai suoi duplicati, ecco un buon metodo per ottenere il codice sorgente per una funzione del pacchetto senza bisogno di sapere in quale pacchetto si trova. Ad esempio, se vogliamo il sorgente per randomForest::rfcv() :

Per visualizzarlo / modificarlo in una finestra pop-up:

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

Per reindirizzare a un file separato :

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

Per le funzioni non primitive, R base include una funzione chiamata body() che restituisce il corpo della funzione. Ad esempio, è possibile visualizzare la fonte della funzione print.Date() :

body(print.Date)

produrrà questo:

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

Se stai lavorando in uno script e vuoi che il codice funzione sia un vettore di caratteri, puoi ottenerlo.

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

ti prenderà:

[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] "}"     

Perché dovrei fare una cosa del genere? Stavo creando un oggetto S3 personalizzato ( x , dove class(x) = "foo" ) basato su un elenco. Uno dei membri della lista (chiamato "fun") era una funzione e volevo print.foo() per visualizzare il codice sorgente della funzione, rientrato. Così ho finito con il seguente frammento in print.foo() :

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

quale rientro e visualizza il codice associato con x[["fun"]] .


Viene rivelato quando esegui il debug usando la funzione debug (). Supponiamo di voler vedere il codice sottostante nella funzione di trasposizione t (). Basta digitare "t", non rivela molto.

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

Ma, usando il 'debug (functionName)', rivela il codice sottostante, sans internals.

> 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 () realizza lo stesso senza dover usare undebug ()


UseMethod("t") ti dice che t() è una funzione generica ( S3 ) che ha metodi per diverse classi di oggetti.

Il sistema di invio del metodo S3

Per le classi S3, è possibile utilizzare la funzione methods per elencare i metodi per una particolare funzione o classe generica.

> 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

"Le funzioni non visibili sono asteriscate" significa che la funzione non viene esportata dal suo spazio dei nomi del pacchetto. Puoi comunque visualizzare il suo codice sorgente tramite la funzione ::: (cioè stats:::t.ts ), o usando getAnywhere() . getAnywhere() è utile perché non devi sapere da quale pacchetto proviene la funzione.

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

Il sistema di invio del metodo S4

Il sistema S4 è un sistema di invio del metodo più recente ed è un'alternativa al sistema S3. Ecco un esempio di una funzione 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.

L'output offre già molte informazioni. standardGeneric è un indicatore di una funzione S4. Il metodo per vedere i metodi definiti S4 viene offerto in modo utile:

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

getMethod può essere usato per vedere il codice sorgente di uno dei metodi:

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

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

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"

Esistono anche metodi con firme più complesse per ciascun metodo, ad esempio

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"

Per vedere il codice sorgente di uno di questi metodi è necessario fornire l'intera firma, ad es

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

Non sarà sufficiente fornire la firma parziale

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

Funzioni che chiamano funzioni non esportate

Nel caso di ts.union , .cbindts e .makeNamesTs sono funzioni non esportate dallo spazio dei nomi delle stats . È possibile visualizzare il codice sorgente delle funzioni non esportate utilizzando l'operatore ::: o 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>

Funzioni che chiamano codice compilato

Si noti che "compilato" non si riferisce al codice R compilato in byte come creato dal pacchetto del compilatore . La riga <bytecode: 0x294e410> nell'output precedente indica che la funzione è compilata in byte e puoi comunque visualizzare l'origine dalla riga di comando R.

Le funzioni che chiamano .C , .Call , .Fortran , .External , .Internal , o .Primitive chiamano i punti di ingresso nel codice compilato, quindi dovrai cercare le fonti del codice compilato se vuoi comprendere appieno la funzione. This mirror GitHub del codice sorgente R è un posto decente per iniziare. La funzione pryr::show_c_source può essere uno strumento utile in quanto ti porterà direttamente a una pagina GitHub per le chiamate .Internal e .Primitive . I pacchetti possono usare .C , .Call , .Fortran e .External ; ma non. .Internal o. .Primitive , perché sono usati per chiamare funzioni incorporate nell'interprete R.

Le chiamate ad alcune delle funzioni di cui sopra possono utilizzare un oggetto invece di una stringa di caratteri per fare riferimento alla funzione compilata. In questi casi, l'oggetto è di classe "NativeSymbolInfo" , "RegisteredNativeSymbol" o "NativeSymbol" ; e la stampa dell'oggetto produce informazioni utili. Ad esempio, .External2(C_optimhess, res$par, fn1, gr1, con) chiamate .External2(C_optimhess, res$par, fn1, gr1, con) (nota che C_optimhess , non "C_optimhess" ). optim è nel pacchetto stats, quindi puoi digitare stats:::C_optimhess per vedere le informazioni sulla funzione compilata chiamata.

Codice compilato in un pacchetto

Se si desidera visualizzare il codice compilato in un pacchetto, è necessario scaricare / decomprimere la sorgente del pacchetto. I file binari installati non sono sufficienti. Il codice sorgente di un pacchetto è disponibile dallo stesso repository CRAN (o CRAN compatibile) dal quale è stato originariamente installato il pacchetto. La funzione download.packages() può ottenere il pacchetto sorgente per te.

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

Questo scaricherà la versione sorgente del pacchetto Matrix e salverà il corrispondente file .tar.gz nella directory corrente. Il codice sorgente per le funzioni compilate può essere trovato nella directory src del file uncompressed e untared. La fase uncompressing e untaring può essere eseguita al di fuori di R o da R usando la funzione untar() . È possibile combinare il passaggio di download e di espansione in una singola chiamata (notare che solo un pacchetto alla volta può essere scaricato e decompresso in questo modo):

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

In alternativa, se lo sviluppo del pacchetto è ospitato pubblicamente (ad esempio tramite GitHub , R-Forge o RForge.net ), è probabilmente possibile sfogliare il codice sorgente online.

Codice compilato in un pacchetto base

Alcuni pacchetti sono considerati pacchetti "base". Questi pacchetti vengono forniti con R e la loro versione è bloccata nella versione di R. Esempi includono base , compiler , stats e programmi di utils . In quanto tali, non sono disponibili come pacchetti scaricabili separati su CRAN come descritto sopra. Piuttosto, fanno parte dell'albero dei sorgenti R nelle singole directory dei pacchetti in /src/library/ . Come accedere alla sorgente R è descritto nella prossima sezione.

Codice compilato incorporato nell'interprete R

Se si desidera visualizzare il codice integrato nell'interprete R, è necessario scaricare / decomprimere i sorgenti R; oppure è possibile visualizzare le fonti online tramite il repository R Subversion o il mirror github di Winston Chang .

L' articolo di notizie R di Uwe Ligges (PDF) (pagina 43) è un buon riferimento generale su come visualizzare il codice sorgente per le funzioni .Internal e .Primitive . I passaggi di base sono di cercare prima il nome della funzione in src/main/names.c e quindi cercare il nome "C-entry" nei file in src/main/* .





r-faq