¿Cómo se puede encontrar un método no importado en un paquete no adjunto mediante llamadas a funciones que no lo tienen en su espacio de nombres?


Un espacio de nombres R actúa como el entorno inmediato para todas las funciones en su paquete asociado. En otras palabras, cuando function bar() from package foo llama a otra función, el evaluador de R primero busca la otra función en <environment: namespace:foo>, luego en "imports.foo", <environment: namespace:base>, <environment: R_GlobalEnv>, y así sucesivamente en la lista de búsqueda devuelta escribiendo search().

Un buen aspecto de los espacios de nombres es que pueden hacer que los paquetes actúen como mejores ciudadanos: funciones no exportadas en <environment: namespace:foo> y funciones en imports:foo solo están disponibles: (a) para funciones en foo; (b) para otros paquetes que importan desde foo; o (c) a través de llamadas a funciones completamente calificadas como foo:::bar().

O eso pensaba hasta hace poco...

El comportamiento

Esta reciente pregunta SO destacó un caso en el que una función bien escondida en el espacio de nombres de su paquete fue encontrada sin embargo por una llamada a una función aparentemente no relacionada:

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

Su causa inmediata

@ Andrie respondió a la pregunta original señalando que gmodels importa desde el paquete gdata, que incluye una función reorder.factor que se envía dentro de la segunda llamada a transform(). T1 difiere de T2 porque el primero se calcula por stats:::reorder.default() y el segundo por gdata:::reorder.factor().

Mi pregunta

¿Cómo es que en la llamada anterior a transform(data, group=reorder(...)), el mecanismo de envío para reorder encuentra y luego envía a gdata:::reorder.factor()?

(Una respuesta debe incluya una explicación de las reglas de alcance que conducen de una llamada que involucra funciones en los paquetes stats y base a un método aparentemente bien oculto en gdata.)


Otros detalles posiblemente útiles

  1. Ni gdata:::reorder.factor, ni el paquete gdata como un todo son explícitamente importados por gmodels. Aquí están las directivas import* en gmodels' ESPACIO DE NOMBRES archivo:

    importFrom(MASS, ginv)
    importFrom(gdata, frameApply)
    importFrom(gdata, nobs)
    
  2. , no Existen métodos para reorder() o {[15] {} en[27]}, ni en "imports:gmodels":

    ls(getNamespace("gmodels"))
    ls(parent.env(getNamespace("gmodels")))
    
  3. Separar gmodels no revierte el comportamiento de reorder(): gdata:::reorder.factor() todavía se envía:

    detach("package:gmodels")
    T3 <- transform(data, group=reorder(group,-num))
    identical(T3, T2)
    # [1] TRUE
    
  4. reorder.factor() no se almacena en la lista de métodos S3 en el entorno base:

    grep("reorder", ls(.__S3MethodsTable__.))
    # integer(0)
    

R hilos de chat de los últimos días incluyen algunas ideas adicionales. Gracias a Andrie, Brian Diggs y Gavin Simpson quién (con otros) debería sentirse libre de editar o agregar posiblemente impt. detalles de esta pregunta.

Author: Community, 2012-06-13

1 answers

No estoy seguro si entiendo correctamente su pregunta, pero el punto principal es que group es vector de caracteres mientras que data$group es factor.

Después de adjuntar gmodels, la llamada para reorder(factor) llama gdata:::reorder.factor. entonces, reorder(factor(group)) lo llama.

En transform, la función se evalúa dentro del entorno del primer argumento, por lo que en T2 <- transform(data, group = reorder(group,-num)), group es factor.

ACTUALIZADO

library adjunta los paquetes de importación al espacio de nombres cargado.

> 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"    

Por si acaso, el reorder genérico existe en namespace:stats:

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

Y para más detalles

La llamada de reorder buscará los S3generics en dos envs:

Véase ?UseMethod

Primero en el entorno en el que se llama a la función genérica, y luego en la base de datos de registro para el entorno en el que se define el genérico (típicamente un espacio de nombres).

Luego, loadNamespace registra las funciones S3 en el espacio de nombres.

Entonces, en su caso, library(gmodels) -> loadNamespace(gdata) -> registerS3Methods(gdata).

Después de esto, se puede encontrar por:

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

   Non-visible functions are asterisked

Sin embargo, como el reorder.factor no está adjunto en su ruta de búsqueda, no puede acceder directamente a él:

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

Probablemente este es todo el escenario.

 15
Author: kohske,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-13 04:26:15