Was bedeutet der Punkt in R - persönliche Präferenz, Namenskonvention oder mehr?

76

Ich beziehe mich (wahrscheinlich) NICHT auf die Bedeutung "alle anderen Variablen" wie var1~.hier. Ich wurde plyrnoch einmal darauf hingewiesen mlplyund habe mich gefragt, warum Parameter mit einem führenden Punkt wie folgt definiert sind:

function (.data, .fun = NULL, ..., .expand = TRUE, .progress = "none", 
.parallel = FALSE) 
{
if (is.matrix(.data) & !is.list(.data)) 
    .data <- .matrix_to_df(.data)
f <- splat(.fun)
alply(.data = .data, .margins = 1, .fun = f, ..., .expand = .expand, 
    .progress = .progress, .parallel = .parallel)
}
<environment: namespace:plyr>

Was nützt das? Ist es nur persönliche Präferenz, Namenskonvention oder mehr? Oft ist R so funktional, dass ich einen Trick vermisse, der schon lange gemacht wurde.

Matt Bannert
quelle
5
Gute Frage. Auch die Verwendung von Punkten in Funktionsnamen ( is.na, as.data.frame, ...) ist nicht üblich , in anderen Programmiersprachen, aber ich mag es.
TMS
Das purrrPaket (purrr.tidyverse.org) fügt jetzt eine weitere Bedeutungsebene wie in ~ .x+1== hinzu function(x) x+1.
Isomorphismen
1
So viel von dieser Verwirrung könnte gelöst werden, wenn Tastaturen den _Schlüssel an einer leicht erreichbaren Stelle platzieren (wie Sie wissen, anstelle eines ShoppingSchlüssels ...)
Isomorphismen

Antworten:

116

Ein Punkt im Funktionsnamen kann Folgendes bedeuten:

  • gar nichts
  • ein Trennzeichen zwischen Methode und Klasse in S3-Methoden
  • um den Funktionsnamen auszublenden

Mögliche Bedeutungen

1. Gar nichts

Der Punkt in data.frametrennt nicht dataaus frame, die nicht visuell.

2. Trennung von Methoden und Klassen in S3-Methoden

plotist ein Beispiel für eine generische S3-Methode. Somit sind plot.lmund plot.glmsind die zugrunde liegenden Funktionsdefinitionen, die beim Aufrufen von plot(lm(...))oder verwendet werdenplot(glm(...))

3. Interne Funktionen ausblenden

Beim Schreiben von Paketen ist es manchmal nützlich, führende Punkte in Funktionsnamen zu verwenden, da diese Funktionen der allgemeinen Ansicht etwas verborgen sind. Funktionen, die nur für ein Paket vorgesehen sind, verwenden dies manchmal.

In diesem Zusammenhang bedeutet "etwas versteckt" einfach, dass die Variable (oder Funktion) normalerweise nicht angezeigt wird, wenn Sie ein Objekt mit auflisten ls(). lsVerwenden Sie, um das Anzeigen dieser Variablen zu erzwingen ls(all.names=TRUE). Indem Sie einen Punkt als Anfangsbuchstaben einer Variablen verwenden, ändern Sie den Bereich der Variablen selbst. Zum Beispiel:

x <- 3
.x <- 4

ls()
[1] "x"

ls(all.names=TRUE)
[1] ".x" "x" 

x
[1] 3
.x
[1] 4

4. Andere mögliche Gründe

Bei Hadley Paket verwendet er die Konvention, um führende Punkte in Funktionsnamen zu verwenden. Dies ist ein Mechanismus, um sicherzustellen, dass beim Auflösen von Variablennamen die Werte in Benutzervariablen und nicht in interne Funktionsvariablen aufgelöst werden.


Komplikationen

Dieses Durcheinander verschiedener Verwendungen kann zu sehr verwirrenden Situationen führen, da diese verschiedenen Verwendungen alle unter demselben Funktionsnamen verwechselt werden können.

Zum Beispiel, um a data.framein eine von Ihnen verwendete Liste zu konvertierenas.list(..)

as.list(iris)

In diesem Fall as.listhandelt es sich um eine generische S3-Methode, an die Sie eine übergeben data.frame. Daher heißt die S3-Funktion as.list.data.frame:

> as.list.data.frame
function (x, ...) 
{
    x <- unclass(x)
    attr(x, "row.names") <- NULL
    x
}
<environment: namespace:base>

Und für etwas wirklich Spektakuläres laden Sie das data.tablePaket und sehen Sie sich die Funktion an as.data.table.data.frame:

> library(data.table)

> methods(as.data.table)
[1] as.data.table.data.frame* as.data.table.data.table* as.data.table.matrix*    

   Non-visible functions are asterisked


> data.table:::as.data.table.data.frame
function (x, keep.rownames = FALSE) 
{
    if (keep.rownames) 
        return(data.table(rn = rownames(x), x, keep.rownames = FALSE))
    attr(x, "row.names") = .set_row_names(nrow(x))
    class(x) = c("data.table", "data.frame")
    x
}
<environment: namespace:data.table>
Andrie
quelle
Was meinst du mit "etwas versteckt" ? Der Punkt ändert den variablen Bereich nicht, oder? Es ist also nur in dem Sinne versteckt, dass Benutzer normalerweise keinen Punkt am Anfang des Variablennamens verwenden, oder?
TMS
@TomasT. Ich habe meine Antwort bearbeitet. Ja, das Hinzufügen eines Punkts ändert den Gültigkeitsbereich xund .xist eine andere Variable. Gepunktete Variablen werden ausgeblendet, da sie nur lsls(all.names=TRUE)
angezeigt werden,
1
Oh, ich verstehe was du meinst. Nein, das Bereichsverhalten für xund .xist das gleiche. Es sind einfach verschiedene Variablen.
Andrie
3
Ich mache das nur in Plyr, weil Sie zwischen Argumenten für die Plyr-Funktion und Argumenten für die Funktion, die Plyr aufruft, unterscheiden möchten.
Hadley
3
Plyr hat auch eine .Funktion. get(".") ; function (..., .env = parent.frame()) { structure(as.list(match.call()[-1]), env = .env, class = "quoted") }
baptiste
28

Zu Beginn eines Namens funktioniert es wie die UNIX-Dateinamenkonvention, Objekte standardmäßig auszublenden.

ls()
character(0)

.a <- 1

ls()
character(0)

ls(all.names = TRUE)
[1] ".a"

Es kann nur ein Token ohne besondere Bedeutung sein, es macht nichts mehr als jedes andere erlaubte Token.

my.var <- 1
my_var <- 1
myVar <- 1

Es wird für den Versand der S3-Methode verwendet. Wenn ich also die einfache Klasse "myClass" definiere und Objekte mit diesem Klassenattribut erstelle, werden generische Funktionen wie print () automatisch an meine spezifische Druckmethode gesendet.

myvar <- 1

print(myvar)

class(myvar) <- c("myClass", class(myvar))

print.myClass <- function(x, ...) {

    print(paste("a special message for myClass objects, this one has length", length(x)))
    return(invisible(NULL))
}

print(myvar)

Die Syntax für S3 weist eine Mehrdeutigkeit auf, da Sie anhand des Funktionsnamens nicht erkennen können, ob es sich um eine S3-Methode oder nur um einen Punkt im Namen handelt. Aber es ist ein sehr einfacher Mechanismus, der sehr mächtig ist.

Zu jedem dieser drei Aspekte gehört noch viel mehr, und Sie sollten meine Beispiele nicht als bewährte Methode betrachten, aber sie sind die grundlegenden Unterschiede.

mdsumner
quelle
3
Warum willst du ein Objekt verstecken, das sowieso nicht global ist?
Matt Bannert
3
Sie können auch eine Variable oder Funktion als einen einzelnen Punkt definieren! Wie .=1oder .(1). Das ist wirklich komisch, besonders in Ausdrücken .*.+.:-)
TMS
0

Wenn ein Benutzer eine Funktion .doSomething definiert und nicht in der Lage ist, die gesamte Sauerstoffdokumentation für Parameter anzugeben, werden beim Kompilieren des Pakets keine Fehler generiert

userJT
quelle