Подтвердить что ты не робот

Как может не импортированный метод в ненастроенном пакете быть вызван вызовами функций, не имеющих его в своем пространстве имен?

Пространство имен 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 импортирует из пакета gdata​​strong > , который включает в себя функцию reorder.factor, которая отправляется во второй вызов до transform(). T1 отличается от T2, потому что первый вычисляется через stats:::reorder.default(), а второй - gdata:::reorder.factor().

Мой вопрос

Как получилось, что в приведенном выше вызове transform(data, group=reorder(...)) механизм диспетчеризации для reorder находит, а затем отправляется на gdata:::reorder.factor()?

(Ответ должен включать объяснение правил определения области видимости, которые приводят к вызову с участием функций в пакетах stats и base, к видимому хорошо скрытому методу в GData​​STRONG > ).


Дополнительные полезные сведения

  • Ни gdata:::reorder.factor, ни пакет gdata​​strong > в целом явно не импортируются 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. подробности на этот вопрос.

4b9b3361

Ответ 1

Я не уверен, правильно ли я понял ваш вопрос, но главное, что group - это вектор символов, а data$group - фактор.

После присоединения gmodels вызов reorder(factor) вызывает gdata:::reorder.factor. поэтому reorder(factor(group)) вызывает его.

В transform функция оценивается в среде первого аргумента, поэтому в T2 <- transform(data, group = reorder(group,-num)), group является фактором.

ОБНОВЛЕНО

library прикрепляет пакеты импорта к загруженному пространству имен.

> loadedNamespaces()
 [1] "RCurl"     "base"      "datasets"  "devtools"  "grDevices" "graphics"  "methods"  
 [8] "stats"     "tools"     "utils"    
> library(gmodels) # here, namespace:gdata is loaded
> loadedNamespaces()
 [1] "MASS"      "RCurl"     "base"      "datasets"  "devtools"  "gdata"     "gmodels"  
 [8] "grDevices" "graphics"  "gtools"    "methods"   "stats"     "tools"     "utils"    

На всякий случай, в namespace:stats существует общий reorder:

> r <- ls(.__S3MethodsTable__., envir = asNamespace("stats"))
> r[grep("reorder", r)]
[1] "reorder"            "reorder.default"    "reorder.dendrogram"

И для более подробной информации

Вызов reorder будет искать S3generics в двух envs:

см. ?UseMethod

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

тогда loadNamespace регистрирует функции S3 в пространстве имен.

Итак, в вашем случае library(gmodels)loadNamespace(gdata)registerS3Methods(gdata).

После этого вы можете найти его по:

> methods(reorder)
[1] reorder.default*    reorder.dendrogram* reorder.factor*    

   Non-visible functions are asterisked

Однако, поскольку reorder.factor не указан в вашем пути поиска, вы не можете получить к нему доступ напрямую:

> reorder.factor
Error: object 'reorder.factor' not found

Возможно, это целый сценарий.