Почему использование назначить плохо?
Этот пост (Ленивая оценка в R - влияет ли назначение?) Охватывает некоторые общие точки, но я не уверен, что он отвечает на мой вопрос.
Я прекратил использование assign
когда обнаружил семейство apply
некоторое время назад, хотя и исключительно по причинам элегантности в таких ситуациях:
names.foo <- letters
values.foo <- LETTERS
for (i in 1:length(names.foo))
assign(names.foo[i], paste("This is: ", values.foo[i]))
который можно заменить на:
foo <- lapply(X=values.foo, FUN=function (k) paste("This is :", k))
names(foo) <- names.foo
Это также причина этого (http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-turn-a-string-into-a-variable_003f) R-faq говорит, что этого следует избегать.
Теперь я знаю, что assign
обычно осуждается. Но есть ли другие причины, о которых я не знаю? Я подозреваю, что это может испортить обзор или ленивую оценку, но я не уверен? Пример кода, который демонстрирует такие проблемы, будет отличным.
Ответы
Ответ 1
На самом деле эти две операции совершенно разные. Первый дает вам 26 разных объектов, а второй дает вам только один. Второй объект будет намного проще использовать в анализах. Поэтому, я думаю, я бы сказал, что вы уже продемонстрировали существенный недостаток assign
, а именно необходимость необходимости всегда использовать get
для корреляции или сбора всех одинаково названных отдельных объектов, которые теперь "потеряны" в глобальном Окружающая среда. Попробуйте представить, как вы будете последовательно делать что-либо с этими 26 отдельными объектами. Для второй стратегии будет достаточно простого lapply(foo, func)
.
В этом разделе часто задаваемых вопросов говорится, что использование присваивания, а затем назначение имен проще, но не означает, что это было "плохо". Я считаю, что это "менее функционально", поскольку вы фактически не возвращаете значение, которое присваивается. Эффект выглядит побочным эффектом (и в этом случае стратегия assign
приводит к 26 отдельным побочным эффектам). Использование assign
, по-видимому, принимается людьми, которые поступают с языков, имеющих глобальные переменные, как способ избежать подбора "True R Way", то есть функционального программирования с объектами данных. Они действительно должны учиться использовать списки, а не засорять рабочее пространство с помощью отдельных элементов.
Существует еще одна парадигма назначения, которая может быть использована:
foo <- setNames( paste0(letters,1:26), LETTERS)
Это создает именованный атомный вектор, а не именованный список, но доступ к значениям в векторе по-прежнему выполняется с именами, указанными в [
.
Ответ 2
В качестве источника fortune(236)
я подумал, что добавлю пару примеров (также см. fortune(174)
).
Во-первых, опрос. Рассмотрим следующий код:
x <- 1
y <- some.function.that.uses.assign(rnorm(100))
После запуска вышеуказанных двух строк кода, каково значение x
?
Функция assign
используется для фиксации "действия на расстоянии" (см. http://en.wikipedia.org/wiki/Action_at_a_distance_ (computer_programming ) или google для него). Это часто является источником трудностей для поиска ошибок.
Я думаю, что самая большая проблема с assign
заключается в том, что она приводит людей к путям мышления, которые отвлекают их от лучших вариантов. Простым примером является 2 набора кода в вопросе. Решение lapply
более элегантно и должно поощряться, но тот факт, что люди узнают о функции assign
, приводит людей к опции цикла. Затем они решают, что им нужно выполнить одну и ту же операцию для каждого объекта, созданного в цикле (это было бы просто еще одна простая lapply
или sapply
, если бы использовалось элегантное решение) и прибегнуть к еще более сложному циклу, включающему как get
и apply
вместе с уродливыми вызовами на paste
. Затем те, кто влюблен в assign
, пытаются сделать что-то вроде:
curname <- paste('myvector[', i, ']')
assign(curname, i)
И это не делает то, что они ожидали, что приводит к жалобам на R (что так же справедливо, как жаловаться на то, что мой соседний соседний дом слишком далеко, потому что я решил пройти долгий путь вокруг блока) или даже хуже, углубиться в использование eval
и parse
, чтобы заставить их построенную строку "работать" (что затем приводит к fortune(106)
и fortune(181)
).
Ответ 3
Я хотел бы указать, что assign
предназначен для использования с environment
s.
С этой точки зрения "плохая" вещь в приведенном выше примере использует не совсем подходящую структуру данных (базовая среда вместо list
или data.frame
, vector
,...).
Боковое примечание: также для environment
s, работают операторы $
и $<-
, поэтому во многих случаях явные assign
и get
там не нужны.