attach dans .onLoad

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Pierre-Yves Berrard
Messages : 662
Enregistré le : 12 Jan 2016, 23:30

attach dans .onLoad

Messagepar Pierre-Yves Berrard » 12 Fév 2019, 14:12

Bonjour,

Dans un package que je conçois, j'ai une liste (maliste) que je rends disponible à l'utilisateur.
Pour plus de confort, je souhaiterais que l'utilisateur puisse accéder aux éléments sans saisir maliste$...
J'envisage donc d'attach()er la liste.

Pour cela, j'avais comme idée d'écrire quelque chose du style dans la fonction .onLoad :

Code : Tout sélectionner

if (!maliste %in% search()) attach(maliste)
et la réciproque dans .onUnload.

Avant de me lancer, j'aimerais savoir si cette solution n'est pas trop "casse-gueule" (je suis d'habitude réticent à utiliser attach).
Auriez-vous éventuellement une meilleure façon de faire ?
PY

Mickael Canouil
Messages : 554
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: attach dans .onLoad

Messagepar Mickael Canouil » 12 Fév 2019, 14:30

Bonjour Pierre-Yves,

les "attach" et toutes autres fonctions/interventions sur l’environnement global ne passent pas les vérifications automatiques du CRAN.
C'est considéré comme une "mauvaise" pratique.
De quelle nature est "maliste" ? (son contenu/utilisation)

Cordialement,
Mickaël

Pierre-Yves Berrard
Messages : 662
Enregistré le : 12 Jan 2016, 23:30

Re: attach dans .onLoad

Messagepar Pierre-Yves Berrard » 12 Fév 2019, 14:47

Merci pour la réponse.

Mickael Canouil a écrit :les "attach" et toutes autres fonctions/interventions sur l’environnement global ne passent pas les vérifications automatiques du CRAN.

Ce package ne sera pas soumis au CRAN.

Mickael Canouil a écrit :C'est considéré comme une "mauvaise" pratique.

Je sais, mais étant donné que je fais ça dans .onLoad, ça m'a paru moins "mauvais" (surtout en détachant proprement au déchargement du package).

Mickael Canouil a écrit :De quelle nature est "maliste" ? (son contenu/utilisation)

C'est une liste de fonctions, dont le but est d'extraire des infos d'un data.frame situé dans les profondeurs d'une autre liste.

L'idée est d'écrire :

Code : Tout sélectionner

maliste$donnees(x, "foo")
# ou comme espéré
donnees(x, "foo")
au lieu de

Code : Tout sélectionner

x$niv1$niv2$niv3$donnees[x$niv1$niv2$niv3$donnees == "foo", ]

Une liste de getters, en quelque sorte. (Ces fonctions sont dans une liste car générées de manière automatique.)
PY

Mickael Canouil
Messages : 554
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: attach dans .onLoad

Messagepar Mickael Canouil » 12 Fév 2019, 15:56

J'ai peut-être raté quelque-chose, mais pourquoi stocker ces fonctions dans une liste, plutôt que les exporter classiquement?
En roxygen2, l'export est fait via le @export, sinon il suffit d'ajouter "export(donnees)" dans le fichier NAMESPACE.

Code : Tout sélectionner

#' donnees
#'
#' @param x
#' @param y
#'
#' @return something
#' @export
donnees <- function(x, y) {
...
}

Une fois le package chargé, la fonction sera accessible depuis l'environnement global.

Pierre-Yves Berrard a écrit :L'idée est d'écrire :

Code : Tout sélectionner

maliste$donnees(x, "foo")
# ou comme espéré
donnees(x, "foo")
au lieu de

Code : Tout sélectionner

x$niv1$niv2$niv3$donnees[x$niv1$niv2$niv3$donnees == "foo", ]

Une liste de getters, en quelque sorte. (Ces fonctions sont dans une liste car générées de manière automatique.)


On dirait du R5 ^^ http://adv-r.had.co.nz/R5.html
Mickaël

Pierre-Yves Berrard
Messages : 662
Enregistré le : 12 Jan 2016, 23:30

Re: attach dans .onLoad

Messagepar Pierre-Yves Berrard » 12 Fév 2019, 16:18

Mickael Canouil a écrit :J'ai peut-être raté quelque-chose, mais pourquoi stocker ces fonctions dans une liste, plutôt que les exporter classiquement?

Car ces fonctions sont générées de manière automatique. Il y en a beaucoup et je n'en connais pas forcément le nombre à l'avance.

Oui R5 (ou R6), mais je me contente de S3 pour l'instant. La partie "objet" de mon package est assez light, hormis cette partie qui n'est pas essentielle.
PY

Mickael Canouil
Messages : 554
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: attach dans .onLoad

Messagepar Mickael Canouil » 12 Fév 2019, 16:33

J'aurai tendance dans ce cas, à créer une fonction générique, quelque-chose comme ci-dessous:

Code : Tout sélectionner

do <- function(x, f, ...){
  x[[f]](x[["data"]], ...)
}

obj <- list(data = rnorm(10), sd = sd, mean = mean)

do(obj, 'sd')
do(obj, 'mean')


edit: j'ai considéré ici qu'il y avait un lien entre l'objet et les fonctions, mais ce n'est peut-être pas le cas...
Mickaël

Pierre-Yves Berrard
Messages : 662
Enregistré le : 12 Jan 2016, 23:30

Re: attach dans .onLoad

Messagepar Pierre-Yves Berrard » 13 Fév 2019, 08:48

Dans l'esprit de ton exemple, voici un exemple plus proche de ce que je cherche à faire :

Code : Tout sélectionner

obj <- list(data = data.frame(id = 1:2, val1 = 11:12, val2 = 101:102))

do <- function(x, id, nom_var) {
  x$data[[nom_var]][x$data$id == id]
}

do(obj, id = 2, nom_var = "val1") # [1] 12
do(obj, id = 1, nom_var = "val2") # [1] 101

do_generator <- function(nom_var) function(x, id) do(x, id, nom_var)

variables <- c("val1", "val2")
maliste_do <- lapply(setNames(variables, variables), do_generator)

maliste_do$val1(obj, 2) # [1] 12
maliste_do$val2(obj, 1) # [1] 101

if (!"maliste_do" %in% search()) attach(maliste_do)
val1(obj, 2) # [1] 12
val2(obj, 1) # [1] 101
if ("maliste_do" %in% search()) detach(maliste_do)

Comme tu le vois, le but est que l'utilisateur n'ait pas à connaître la fonction do().
PY

Eric Wajnberg
Messages : 656
Enregistré le : 11 Aoû 2008, 15:37
Contact :

Re: attach dans .onLoad

Messagepar Eric Wajnberg » 13 Fév 2019, 09:45

Juste une question naïve :

Pourquoi ne pas attaché de toute façon cet objet. S'il est déjà dans search(), il sera attaché une seconde fois. Et alors ?

HTH, Eric.

Pierre-Yves Berrard
Messages : 662
Enregistré le : 12 Jan 2016, 23:30

Re: attach dans .onLoad

Messagepar Pierre-Yves Berrard » 13 Fév 2019, 10:15

@ Eric : attacher n fois un objet fait qu'il apparaît n fois dans search(). Cela génère des messages avertissant des masquages et surtout, si l'on veut détacher proprement après utilisation, ça me paraît plus simple de s'assurer que le nom n'apparaît qu'une fois.

Ceci dit, il est possible que j'aie une compréhension limitée des conséquences d'utiliser attach. D'où ma recherche de conseils sur le forum !
PY

Eric Wajnberg
Messages : 656
Enregistré le : 11 Aoû 2008, 15:37
Contact :

Re: attach dans .onLoad

Messagepar Eric Wajnberg » 13 Fév 2019, 10:19

Oui, je sais bien. Mais je répète la question : Et alors ?

Ce ne sont que des warnings, et il suffit de détacher ce qui a été attaché auparavant, et l'on retrouve le système dans son état initial.

Eric.

Pierre-Yves Berrard
Messages : 662
Enregistré le : 12 Jan 2016, 23:30

Re: attach dans .onLoad

Messagepar Pierre-Yves Berrard » 13 Fév 2019, 10:34

Alors effectivement, je pourrais enlever les vérifications sur la présence dans search() et ça marcherait tout aussi bien. Mais si je les laisse ça marche quand même, non ?

En fait, je voulais montrer que je souhaitais polluer au minimum l'environnement de travail de l'utilisateur, mais c'est une problématique un peu annexe qui vient parasiter l'exemple.
Mon souci principal est l'ergonomie pour l'utilisateur du package (i.e. ne pas l'embêter avec les objets do ou maliste).
PY

Mickael Canouil
Messages : 554
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: attach dans .onLoad

Messagepar Mickael Canouil » 13 Fév 2019, 10:36

Selon l'utilisation, la diffusion, et d'autres critères de ce genre, l'utilisation de attach ou autre n'est pas forcément gênante comme le souligne Eric.

Maintenant, pour vraiment proposer une alternative "élégante" et surtout adaptée, la méthode de construction de cette liste de fonctions pourrait aider.
(Est-ce que ce package en développement se trouve sur une plateforme de développement comme bitbucket ou github par exemple ?)
Mickaël

Pierre-Yves Berrard
Messages : 662
Enregistré le : 12 Jan 2016, 23:30

Re: attach dans .onLoad

Messagepar Pierre-Yves Berrard » 13 Fév 2019, 10:39

Non le code source est uniquement sur le réseau de mon travail.

Pour la méthode de construction de la liste, lapply(..., do_generator) n'aide pas à comprendre ?
Je remets une version épurée de mon exemple précédent :

Code : Tout sélectionner

obj <- list(data = data.frame(id = 1:2, val1 = 11:12, val2 = 101:102))

do <- function(x, id, nom_var) x$data[[nom_var]][x$data$id == id]
do_generator <- function(nom_var) function(x, id) do(x, id, nom_var)

variables <- c("val1", "val2")
maliste_do <- lapply(setNames(variables, variables), do_generator)

attach(maliste_do)
val1(obj, 2)
val2(obj, 1)
detach(maliste_do)
PY

Mickael Canouil
Messages : 554
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: attach dans .onLoad

Messagepar Mickael Canouil » 13 Fév 2019, 11:51

Au temps pour moi, j'avais raté un message.

Le "attach" est très dangereux dans ce cas, puisque les fonctions d'un objet A pourraient écraser celle d'un objet B.
De plus, il pourrait y avoir un conflit entre les fonctions spécifiques de l'objet et celles chargés par différent packages.

En S4 (je n'ai jamais fait de S3), j'aurai défini une méthode '[', un exemple rapide:

Code : Tout sélectionner

myclass <- setClass(
  Class = "myclass",
  slots = c(list = "list")
)

setMethod(f = "[", signature = "myclass", definition = function (x, i, j, drop){
  y <- x@list
  y$data[[j]][y$data$id == i]
})

obj <- list(data = data.frame(id = 1:2, val1 = 11:12, val2 = 101:102))
obj_s4 <- myclass(list = obj))
obj_s4[1, 'val1']

A deux caractères près, c'est la même chose, mais plus "propre" et moins "risqué".
Mickaël

Pierre-Yves Berrard
Messages : 662
Enregistré le : 12 Jan 2016, 23:30

Re: attach dans .onLoad

Messagepar Pierre-Yves Berrard » 13 Fév 2019, 12:55

Bonne idée, je ne devrais pas avoir trop de mal à transposer ça en S3.
PY


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité

cron