¿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
-
Ni
gdata:::reorder.factor
, ni el paquete gdata como un todo son explícitamente importados por gmodels. Aquí están las directivasimport*
en gmodels' ESPACIO DE NOMBRES archivo:importFrom(MASS, ginv) importFrom(gdata, frameApply) importFrom(gdata, nobs)
-
, no Existen métodos para
reorder()
o {[15] {} en[27]}, ni en"imports:gmodels"
:ls(getNamespace("gmodels")) ls(parent.env(getNamespace("gmodels")))
-
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
-
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.
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.
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