Пространство имен R действует как непосредственная среда для всех функций в соответствующем пакете. Другими словами, когда функция bar()
из пакета foo вызывает другую функцию, оценщик R сначала ищет другую функцию в <environment: namespace:foo>
, затем в "imports.foo"
, <environment: namespace:base>
, <environment: R_GlobalEnv>
, и т.д. вниз по списку поиска, возвращаемому путем ввода search()
.
Один приятный аспект пространств имен заключается в том, что они могут делать пакеты лучше, чем лучшие граждане: недоступные функции в <environment: namespace:foo>
и функции в imports:foo
доступны только: (a) для функций в foo; (b) другим пакетам, импортирующим из foo; или (c) с помощью полнофункциональных вызовов функций, таких как foo:::bar()
.
Или так я думал до недавнего времени...
Поведение
Этот недавний вопрос SO выделил случай, когда функция, хорошо скрытая в пространстве имен пакетов, тем не менее была найдена вызовом, казалось бы, несвязанной функции:
group <- c("C","F","D","B","A","E")
num <- c(12,11,7,7,2,1)
data <- data.frame(group,num)
## Evaluated **before** attaching 'gmodels' package
T1 <- transform(data, group = reorder(group,-num))
## Evaluated **after** attaching 'gmodels
library(gmodels)
T2 <- transform(data, group = reorder(group,-num))
identical(T1, T2)
# [1] FALSE
Его непосредственная причина
@Andrie ответил на исходный вопрос, указав, что gmodels импортирует из пакета gdatastrong > , который включает в себя функцию reorder.factor
, которая отправляется во второй вызов до transform()
. T1
отличается от T2
, потому что первый вычисляется через stats:::reorder.default()
, а второй - gdata:::reorder.factor()
.
Мой вопрос
Как получилось, что в приведенном выше вызове transform(data, group=reorder(...))
механизм диспетчеризации для reorder
находит, а затем отправляется на gdata:::reorder.factor()
?
(Ответ должен включать объяснение правил определения области видимости, которые приводят к вызову с участием функций в пакетах stats и base, к видимому хорошо скрытому методу в GDataSTRONG > ).
Дополнительные полезные сведения
-
Ни
gdata:::reorder.factor
, ни пакет gdatastrong > в целом явно не импортируются gmodels. Вот директивыimport*
в файле gmodels ' NAMESPACE:importFrom(MASS, ginv) importFrom(gdata, frameApply) importFrom(gdata, nobs)
-
Нет методов для
reorder()
илиtransform()
в<environment: namespace:gmodels>
, а не в"imports:gmodels"
:ls(getNamespace("gmodels")) ls(parent.env(getNamespace("gmodels")))
-
Отсоединение gmodels не возвращает
reorder()
поведение:gdata:::reorder.factor()
по-прежнему отправляется:detach("package:gmodels") T3 <- transform(data, group=reorder(group,-num)) identical(T3, T2) # [1] TRUE
-
reorder.factor()
не сохраняется в списке методов S3 в базовой среде:grep("reorder", ls(.__S3MethodsTable__.)) # integer(0)
R chat за последние пару дней включают некоторые дополнительные идеи. Спасибо Andrie, Брайан Диггс и Гэвин Симпсон, которые (с другими) должны отредактировать или добавить возможно impt. подробности на этот вопрос.