Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: Matt BannertОтветов: 3

Я (вероятно) НЕ имею в виду "все остальные переменные", означающие здесь 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 настолько функционален, что я упускаю трюк, который давно применялся раньше.

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

rnaming-conventionsplyrcoding-style

Ответы

Ответ 1 · рейтинг 121 · Andrie

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

  • вообще ничего
  • разделитель между методом и классом в методах 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>

Ответ 2 · рейтинг 28 · mdsumner

В начале имени он работает как соглашение об именах файлов 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 или просто точкой в ​​имени. Но это очень простой и очень мощный механизм.

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

Ответ 3 · userJT

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы