Что означает точка в R — личное предпочтение, соглашение об именах или что-то еще?

Я (вероятно) НЕ имею в виду «все остальные переменные», означающие здесь var1~.. Мне снова указали на plyr, и я посмотрел на mlply и удивился, почему параметры определяются с начальной точкой вот так:

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>

Какая от этого польза? Это просто личные предпочтения, соглашение об именах или что-то еще? Часто R настолько функционален, что я упускаю трюк, который давно применялся раньше.


person Matt Bannert    schedule 23.09.2011    source источник
comment
Хороший вопрос. Также использование точек в именах функций (is.na, as.data.frame, ...) не является обычным в других языках программирования, но мне это нравится.   -  person Tomas    schedule 23.09.2011
comment
Дальнейшее объяснение: stats.stackexchange.com/questions/10712/   -  person leo9r    schedule 20.05.2014
comment
Пакет purrr (purrr.tidyverse.org) теперь добавляет еще один уровень смысла, как в ~ .x+1 == function(x) x+1.   -  person isomorphismes    schedule 07.09.2017
comment
Так много этой путаницы можно было бы решить, если бы клавиатура поместила клавишу _ в легкодоступное место (например, вместо клавиши Shopping…)   -  person isomorphismes    schedule 07.09.2017


Ответы (3)


Точка в имени функции может означать любое из следующего:

  • вообще ничего
  • разделитель между методом и классом в методах S3
  • чтобы скрыть имя функции

Возможные значения

1. Ничего

Точка в data.frame не отделяет data от frame, кроме как визуально.

2. Разделение методов и классов в методах S3

plot — это один из примеров универсального метода S3. Таким образом, plot.lm и plot.glm являются базовыми определениями функций, которые используются при вызове plot(lm(...)) или plot(glm(...)).

3. Скрыть внутренние функции

При написании пакетов иногда полезно использовать начальные точки в именах функций, потому что эти функции несколько скрыты от общего вида. Иногда это используют функции, которые должны быть чисто внутренними по отношению к пакету.

В этом контексте «несколько скрыто» просто означает, что переменная (или функция) обычно не отображается, когда вы перечисляете объект с помощью ls(). Чтобы заставить ls показывать эти переменные, используйте ls(all.names=TRUE). Используя точку в качестве первой буквы переменной, вы изменяете область действия самой переменной. Например:

x <- 3
.x <- 4

ls()
[1] "x"

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

x
[1] 3
.x
[1] 4

4. Другие возможные причины

В пакете Хэдли plyr он использует соглашение для использования начальные точки в именах функций. Это как механизм, чтобы попытаться гарантировать, что при разрешении имен переменных значения разрешаются в пользовательские переменные, а не во внутренние переменные функции.


Осложнения

Эта мешанина различных применений может привести к очень запутанным ситуациям, потому что все эти различные применения могут быть перепутаны в одном и том же имени функции.

Например, чтобы преобразовать data.frame в список, вы используете as.list(..).

as.list(iris)

В этом случае as.list является универсальным методом S3, и вы передаете ему data.frame. Таким образом, функция S3 называется as.list.data.frame:

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

А для чего-то действительно впечатляющего загрузите пакет data.table и посмотрите на функцию 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>
person Andrie    schedule 23.09.2011
comment
Что вы имеете в виду под несколько скрытым? Точка не меняет область действия переменной, не так ли? Так что это скрыто только в том смысле, что пользователи обычно не используют точку в начале имени переменной, верно? - person Tomas; 23.09.2011
comment
@ТомасТ. Я отредактировал свой ответ. Да, добавление точки меняет область видимости, поэтому x и .x — разные переменные. Пунктирные переменные скрыты, потому что они не отображаются в ls, если вы не используете ls(all.names=TRUE) - person Andrie; 23.09.2011
comment
но это не то, что обычно является мясом с размахом. Область действия обычно используется с точки зрения глобальной/локальной (для функции, пакета и т. д.), а не просто скрыта в ls() (но все еще доступна). - person Tomas; 23.09.2011
comment
О, я понимаю, что вы имеете в виду. Нет, поведение областей для x и .x одинаково. Просто это разные переменные. - person Andrie; 23.09.2011
comment
Я делаю это только в plyr, потому что вы хотите различать аргументы функции plyr и аргументы функции, которую plyr вызывает. - person hadley; 24.09.2011
comment
@hadley Спасибо за комментарий - я соответствующим образом отредактировал свой ответ. - person Andrie; 24.09.2011
comment
plyr также имеет функцию .. get(".") ; function (..., .env = parent.frame()) { structure(as.list(match.call()[-1]), env = .env, class = "quoted") } - person baptiste; 25.09.2011
comment
Кроме того, в контексте вызова функции с помощью ... вы можете столкнуться с двумя точками, как в foo = function(...) print(..2) ; foo("a", "b", "c"). - person baptiste; 25.09.2011
comment
Это действительно сбивает с толку, почему они не придерживались одного поведения, это сделало бы вещи намного более понятными... - person Vlady Veselinov; 25.02.2018

В начале имени он работает как соглашение об именах файлов UNIX, чтобы по умолчанию объекты были скрыты.

ls()
character(0)

.a <- 1

ls()
character(0)

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

Это может быть просто токен без особого значения, он не делает ничего большего, чем любой другой разрешенный токен.

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

Он используется для отправки метода S3. Итак, если я определяю простой класс «myClass» и создаю объекты с этим атрибутом класса, то общие функции, такие как print(), будут автоматически отправляться в мой конкретный метод печати.

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)

В синтаксисе S3 присутствует двусмысленность, поскольку по имени функции нельзя сказать, является ли она методом S3 или просто точкой в ​​имени. Но это очень простой и очень мощный механизм.

Каждый из этих трех аспектов включает в себя гораздо больше, и вы не должны воспринимать мои примеры как хорошую практику, но они являются основными отличиями.

person mdsumner    schedule 23.09.2011
comment
Почему вы хотите скрыть какой-то объект, который в любом случае не является глобальным? - person Matt Bannert; 23.09.2011
comment
Вы также можете определить переменную или функцию как одну точку! Например, .=1 или .(1). Это действительно странно, особенно в выражениях .*.+. :-) - person Tomas; 23.09.2011

Если пользователь определяет функцию .doSomething и ленится указывать всю документацию roxygen по параметрам, он не выдаст ошибок при компиляции пакета

person userJT    schedule 04.11.2019