Comment puis-je voir le code source d'une fonction?

j'ai envie de regarder le code source d'une fonction pour voir comment il fonctionne. Je sais que je peux imprimer une fonction en tapant son nom à l'invite:

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

Dans ce cas, que signifie UseMethod("t") ? Comment puis-je trouver le code source qui est effectivement utilisé, par exemple: t(1:10) ?

Est-il une différence entre quand je vois UseMethod et quand je vois standardGeneric et showMethods , comme 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.

dans d'autres cas, je peux voir que des fonctions R sont appelées, mais je ne trouve pas le code source de ces fonctions.

> 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

Comment trouver des fonctions comme .cbindts et .makeNamesTs ?

dans d'autres cas, il y a un peu de code R, mais la plupart du travail semble être fait ailleurs.

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

Comment puis-je savoir ce que fait la fonction .Primitive ? De même, certains fonctions Appel .C , .Call , .Fortran , .External , ou .Internal . Comment puis-je trouver le code source pour ceux?

425
demandé sur MichaelChirico 2013-10-07 17:58:00
la source

9 ответов

UseMethod("t") vous dit que t() est une fonction générique ( S3 ) qui a des méthodes pour différentes classes d'objets.

La S3 méthode de système de répartition

pour les classes S3, vous pouvez utiliser la fonction methods pour lister les méthodes pour une fonction ou classe générique particulière.

> 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

"Non-visible les fonctions marquées d'un astérisque sont" signifie que la fonction n'est pas exporté à partir de son paquet de noms. Vous pouvez toujours voir son code source via la fonction ::: (i.e. stats:::t.ts ), ou en utilisant getAnywhere() . getAnywhere() est utile parce que vous n'avez pas à savoir de quel paquet provient la fonction.

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

La S4 méthode de système de répartition

le système S4 est un nouveau système de régulation des méthodes et constitue une solution de rechange au système S3. Voici un exemple de fonction 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.

La sortie offre déjà beaucoup d'informations. standardGeneric est un indicateur d'une fonction S4. La méthode pour voir défini S4 méthodes est offert à titre d'aide:

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

getMethod peut être utilisé pour voir le code source de l'une des méthodes:

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

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

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"

il existe aussi des méthodes avec des signatures plus complexes pour chaque méthode, par exemple

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"

Pour voir le code source de l'un de ces méthodes la signature entière doit être fournie, p.ex.

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

il ne suffit pas de fournir la signature partielle

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

fonctions faisant appel à des fonctions non utilisées

dans le cas de ts.union , .cbindts et .makeNamesTs sont des fonctions non utilisées de l'espace de noms stats . Vous pouvez consulter le code source des fonctions non-triées en utilisant l'opérateur ::: ou 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>

fonctions qui appellent le code compilé

notez que" compilé "ne fait pas référence au code R compilé par byte tel que créé par le paquet compilateur . La ligne <bytecode: 0x294e410> dans la sortie ci-dessus indique que la fonction est byte-compiled, et vous pouvez toujours voir la source à partir de la ligne de commande R.

fonctions qui appellent .C , .Call , .Fortran , .External , .Internal , ou .Primitive appellent les points d'entrée dans le code compilé, donc vous devrez regarder les sources du code compilé si vous voulez pleinement comprendre la fonction. ce" miroir Github 1519680920 " du code source R est un bon endroit pour commencer. La fonction pryr::show_c_source peut être un outil utile car elle vous mènera directement à une page GitHub pour les appels .Internal et .Primitive . Les colis peuvent utiliser .C , .Call , .Fortran , et .External ; mais pas .Internal ou .Primitive , car ils sont utilisés pour appeler des fonctions intégrées dans l'interpréteur R.

les appels à certaines des fonctions ci-dessus peuvent utiliser un objet au lieu d'une chaîne de caractères pour faire référence à la fonction compilée. Dans ces cas, l'objet est de la classe "NativeSymbolInfo" , "RegisteredNativeSymbol" , ou "NativeSymbol" ; et l'impression de l'objet fournit des informations utiles. Par exemple, optim appelle .External2(C_optimhess, res$par, fn1, gr1, con) (notez que c'est C_optimhess , pas "C_optimhess" ). optim est dans le paquet stats, donc vous pouvez taper stats:::C_optimhess pour voir les informations sur la fonction compilée qui est appelée.

code compilé dans un paquet

si vous voulez voir le code compilé dans un paquet, vous devez télécharger/déballer la source du paquet. Les binaires installés ne sont pas suffisants. Le code source d'un paquet est disponible dans le même dépôt CRAN (ou compatible CRAN) que le paquet était initialement installé. La fonction download.packages() peut obtenir le paquet source pour vous.

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

ceci téléchargera la version source du paquet Matrix et enregistrera le fichier .tar.gz correspondant dans le répertoire courant. Le code Source des fonctions compilées peut être trouvé dans le répertoire src du fichier non compressé et non compilé. L'étape de démêlage et de démêlage peut être effectuée en dehors de R , ou de l'intérieur de R en utilisant la fonction untar() . Il est possible de combiner l'étape de téléchargement et d'extension en un seul appel (notez qu'un seul paquet à la fois peut être téléchargé et déballé de cette façon):

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

alternativement, si le développement du paquet est hébergé publiquement (par exemple via GitHub , R-Forge , ou RForge.net ), vous pouvez probablement parcourir le code source en ligne.

code compilé dans un paquet de base

certains colis sont considérés comme des colis de base. Ces paquets sont livrés avec R et leur version est verrouillée sur la version de R. exemples: base , compiler , stats , et utils . À ce titre, ils ne sont pas disponibles sous forme de paquets téléchargeables distincts sur CRAN comme décrit ci-dessus. Ils font plutôt partie de L'arborescence des sources R dans les répertoires de paquets individuels sous /src/library/ . Comment accéder au R la source est décrite dans la section suivante.

code compilé intégré dans l'interpréteur r

si vous voulez visualiser le code intégré à l'interpréteur R, Vous devez télécharger/déballer les sources R; ou vous pouvez visualiser les sources en ligne via le R Subversion repository ou Winston Chang's GitHub mirror .

Uwe Ligges R news article (PDF) (p. 43) est une bonne référence générale sur la façon de visualiser le code source pour les fonctions .Internal et .Primitive . Les étapes de base sont d'abord de rechercher le nom de la fonction dans src/main/names.c , puis de rechercher le nom de la" entrée C "dans les fichiers dans src/main/* .

408
répondu Joshua Ulrich 2017-05-23 14:47:26
la source

en plus des autres réponses sur cette question et ses doublons, voici un bon moyen d'obtenir du code source pour une fonction de paquet sans avoir besoin de savoir dans quel paquet il est. par exemple, si nous voulons la source pour randomForest::rfcv() :

À consulter/modifier 151970920" dans une fenêtre pop-up:

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

à rediriger vers un fichier séparé :

capture.output(getAnywhere('rfcv'), file='source_rfcv.r')
79
répondu smci 2015-09-29 21:58:39
la source

il se révèle quand vous déboguez en utilisant la fonction debug (). Supposons que vous voulez voir le code sous-jacent dans la fonction T() transposer. Taper " t " ne révèle pas grand-chose.

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

mais, en utilisant le 'debug(functionName)', il révèle le code sous-jacent, sans les internes.

> 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 () accomplit la même chose sans avoir à utiliser undebug ()

21
répondu Selva 2014-08-20 07:33:34
la source

N'a pas vu comment cela s'insérait dans le flux de la réponse principale mais il m'a coincé pendant un certain temps donc je l'ajoute ici:

Opérateurs Infix

pour voir le code source de certains opérateurs de base infix (e.g., %% , %*% , %in% ), utiliser getAnywhere , par exemple:

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

la réponse principale couvre Comment puis utiliser des miroirs pour creuser plus profond.

13
répondu MichaelChirico 2016-07-29 22:30:53
la source

Pour les non-primitives de fonctions, de R de base inclut une fonction appelée body() qui retourne le corps de la fonction. Par exemple, la source de la fonction print.Date() peut être consultée:

body(print.Date)

produira ceci:

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

si vous travaillez dans un script et que vous voulez le code de fonction comme vecteur de caractères, vous pouvez l'obtenir.

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

vous obtiendrez:

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

Pourquoi voudrais-je faire une telle chose? Je créais un objet custom S3 ( x , où class(x) = "foo" ) basé sur une liste. Un des membres de la liste (nommé "fun") était une fonction et je voulais print.foo() pour afficher le code source de la fonction, en retrait. Je me suis donc retrouvé avec l'extrait suivant dans print.foo() :

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

qui indente et affiche le code associé à x[["fun"]] .

11
répondu Geoffrey Poole 2017-01-10 02:34:04
la source

il y a une fonction très pratique dans R edit

new_optim <- edit(optim)

il ouvrira le code source de optim en utilisant l'éditeur spécifié dans R options , puis vous pourrez l'éditer et assigner la fonction modifiée à new_optim . J'aime cette fonction très bien pour afficher le code ou de déboguer le code, e.g, impression des messages ou des variables ou même de les affecter à des variables globales pour complément d'enquête (bien sûr, vous pouvez utiliser le bouton debug ).

si vous voulez juste voir le code source et ne voulez pas que le code source long ennuyeux imprimé sur votre console, vous pouvez utiliser

invisible(edit(optim))

clairement, cela ne peut pas être utilisé pour visualiser le code source C/C++ ou Fortran.

BTW, edit peut ouvrir d'autres objets comme list, matrix, etc, qui montre ensuite la structure des données avec des attributs ainsi. La fonction de peut être utilisée pour ouvrir un éditeur excel (si GUI supporte it) pour modifier la matrice ou le cadre de données et retourner le nouveau. Cela est pratique parfois, mais devrait être évitée dans les cas habituels, en particulier lorsque vous matrice est grande.

6
répondu Eric 2014-12-05 02:39:33
la source

aussi longtemps que la fonction est écrite en R PUR et non en C++/Fortran, on peut utiliser ce qui suit. Sinon, le meilleur moyen est débogage et en utilisant " saut dans ":

> functionBody(functionName)
3
répondu MCH 2017-02-08 13:56:34
la source

View([function_name]) - eg. View(mean) assurez-vous d'utiliser uppercase [V]. Le code en lecture seule s'ouvrira dans l'éditeur.

2
répondu Koo 2017-01-11 05:45:22
la source

, Vous pouvez également essayer d'utiliser print.function() , qui est S3 générique, pour obtenir la fonction écrire dans la console.

2
répondu strboul 2017-12-26 14:45:54
la source

Autres questions sur r function r-faq