695 Stimmen

Wie kann ich den Quellcode für eine Funktion anzeigen?

Ich möchte den Quellcode einer Funktion betrachten, um zu sehen, wie sie funktioniert. Ich weiß, dass ich eine Funktion drucken kann, indem ich ihren Namen am Prompt eingebe:

> t
function (x) 
UseMethod("t")

In diesem Fall, was bedeutet UseMethod("t")? Wie finde ich den tatsächlich verwendeten Quellcode, zum Beispiel bei: t(1:10)?

Gibt es einen Unterschied zwischen dem, wenn ich UseMethod sehe, und wenn ich standardGeneric und showMethods sehe, wie bei with?

> with
standardGeneric für "with" definiert aus Paket "base"

function (data, expr, ...) 
standardGeneric("with")

Methoden können für Argumente definiert werden: data
Verwenden Sie  showMethods("with")  für derzeit verfügbare.

In anderen Fällen sehe ich, dass R-Funktionen aufgerufen werden, aber ich kann den Quellcode für diese Funktionen nicht finden.

> ts.union
function (..., dframe = FALSE) 
.cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE)

> .cbindts
Fehler: Objekt '.cbindts' nicht gefunden
> .makeNamesTs
Fehler: Objekt '.makeNamesTs' nicht gefunden

Wie finde ich Funktionen wie .cbindts und .makeNamesTs?

In anderen Fällen gibt es ein bisschen R-Code, aber die meiste Arbeit scheint an anderer Stelle erledigt zu werden.

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

> .Internal
function (call)  .Primitive(".Internal")
> .Primitive
function (name)  .Primitive(".Primitive")

Wie finde ich heraus, was die Funktion .Primitive macht? Ebenso rufen einige Funktionen .C, .Call, .Fortran, .External oder .Internal auf. Wie finde ich den Quellcode dafür?

115voto

smci Punkte 29317

Zusätzlich zu den anderen Antworten auf diese Frage und deren Duplikate, hier ist eine gute Möglichkeit, den Quellcode für eine Package-Funktion zu erhalten, ohne zu wissen, in welchem Package sie sich befindet. z.B. wenn wir den Quellcode für randomForest::rfcv() möchten:

Um ihn in einem Popup-Fenster anzusehen/bearbeiten:

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

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

Beachten Sie, dass edit() einen Texteditor öffnet (nach Wahl des Benutzers), während View() einen tabellenartigen Datensichter aufruft.

  • View() ist großartig zum Durchblättern (mehrspaltiger) Daten, aber normalerweise schrecklich für den Code von allem anderen als Spielzeuglänge.
  • deshalb, wenn man nur Code anzeigen möchte, ist edit() meiner Meinung nach tatsächlich viel besser als View(), da man mit edit() alle Argument-Parser/Überprüfungen/Standard/Fehlermeldungslogik zusammenfalten/ausblenden/dummyisieren kann, die bis zu 70% einer R-Funktion ausmachen können, und einfach zu dem Teil gelangen, in dem die Funktion tatsächlich operationell etwas tut(!), welche Art(en) von Objekten ihr Rückgabetyp ist, ob und wie sie sich rekursiv aufruft, usw.

Um auf eine separate Datei umzuleiten (damit Sie den Code in Ihrem bevorzugten IDE/Editor öffnen/verarbeiten können):

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

35voto

Geoffrey Poole Punkte 1012

Bei nicht-primitiven Funktionen enthält das R-Basispaket eine Funktion namens body(), die den Funktionsrumpf zurückgibt. Zum Beispiel kann der Quellcode der Funktion print.Date() angezeigt werden:

body(print.Date)

liefert dies:

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

Wenn Sie in einem Skript arbeiten und den Funktionscode als Zeichenvektor haben möchten, können Sie ihn erhalten.

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

wird Ihnen Folgendes geben:

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

Warum sollte ich so etwas tun wollen? Ich habe ein benutzerdefiniertes S3-Objekt (x, wobei class(x) = "foo") basierend auf einer Liste erstellt. Eines der Listenelemente (mit Namen "fun") war eine Funktion und ich wollte, dass print.foo() den Funktionsquellcode eingerückt anzeigt. Also hatte ich den folgenden Ausschnitt in print.foo():

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

der den mit x[["fun"]] verbundenen Code einrückt und anzeigt.

Bearbeitung 2020-12-31

Ein weniger umständlicher Weg, um denselben character-Vektor des Quellcodes zu erhalten, ist:

sourceVector = deparse(body(x$fun))

31voto

Selva Punkte 1925

Es wird offengelegt, wenn Sie mit der Funktion debug() debuggen. Angenommen, Sie möchten den zugrunde liegenden Code in der t() Transponierungsfunktion sehen. Nur 't' tippen, enthüllt nicht viel.

>t 
function (x) 
UseMethod("t")

Aber mit 'debug(Funktionsname)' wird der zugrunde liegende Code offenbart, ohne die Interna.

> debug(t)
> t(co2)
debuggen in: t(co2)
debug: UseMethod("t")
Browse[2]> 
debuggen 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)

BEARBEITEN: debugonce() erreicht dasselbe, ohne undebug() verwenden zu müssen

22voto

MichaelChirico Punkte 32476

Nicht gesehen, wie das in den Fluss der Hauptantwort passt, aber es hat mich eine Weile aufgehalten, also füge ich es hier hinzu:

Infix-Operatoren

Um den Quellcode einiger basisinfixoperatoren (z. B. %%, %*%, %in%) zu sehen, verwenden Sie getAnywhere, z. B.:

getAnywhere("%%")
# Es wurde ein einzelnes Objekt gefunden, das zu ‘%%’ passt
# Es wurde an folgenden Orten gefunden
#   Paket:base
#   Namensraum:base
#  mit Wert
#
# Funktion (e1, e2)  .Primitive("%%")

Die Hauptantwort erklärt dann, wie Sie Spiegel verwenden können, um tiefer zu graben.

15voto

Arthur Yip Punkte 5092

In RStudio gibt es (mindestens) 3 Möglichkeiten:

  1. Drücken Sie die F2-Taste, während der Cursor auf einer Funktion steht.
  2. Klicken Sie auf den Funktionsnamen, während Sie die Strg- oder Befehlstaste gedrückt halten.
  3. View(Funktionsname) (wie oben erwähnt)

Ein neues Fenster mit dem Quellcode wird geöffnet. Wenn Sie auf .Primitive oder .C stoßen, benötigen Sie eine andere Methode, tut mir leid.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X