Changer la veleur d'une variable au sein d'une fonction

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

Maxime Hervé
Messages : 427
Enregistré le : 03 Mar 2010, 14:21
Contact :

Changer la veleur d'une variable au sein d'une fonction

Messagepar Maxime Hervé » 14 Déc 2010, 09:09

Bonjour à tous,

j'ai un problème qui me semble très simple, avec je suis sûr une solution très simple, mais je ne la trouve pas :)

En fait, je veux :
- définir une variable à l'intérieure d'une 1ère fonction
- appeler une 2ème fonction à l'intérieur de la 1ère, qui va changer la valeur de cette variable
- que la suite de l'exécution de la 1ère fonction (après appel de la 2ème) prenne en compte la valeur modifiée

Ce que je ne veux pas :
- assigner toutes mes variables à l'environnement global. Je travaille en effet sur une interface Tcl/Tk qui contient des dizaines de variables, et je ne veux pas toutes les stocker dans l'environnement global (mais uniquement que chacune reste à sa place, dans sa fonction)
- relancer la 1ère fonction avec la nouvelle valeur de la variable. Car vu que mes fonctions ouvrent en fait des fenêtres, cela rouvrirait une fenêtre déjà ouverte (et ainsi de suite à chaque appel de la 2ème fonction)

Pour tester le truc je travaille sur le code suivant :

Code : Tout sélectionner

fonction1=function() {
  x=1
  cat(paste("------ Fonction 1 : avant fonction 2 ------\nx=",x,"\n",sep=""))
  if (x==1) {function2(valeur=x)}
  cat(paste("------ Fonction 1 : après function 2 ------\nx=",x,"\n",sep=""))
}

function2=function(valeur) {
  valeur=valeur+1
  cat(paste("------ Fonction 2 ------\nx=",valeur,"\n",sep=""))
  # assign("x",valeur,envir=??)
}


L'objectif étant simplement qu'après appel de la fonction1, les 3 résultats renvoyés soient (dans l'ordre) : "x=1" "x=2" "x=2"

Je pense qu'il faut utiliser la fonction assign(), mais je ne trouve pas comment renseigner l'argument envir...

Merci d'avance,

Maxime

Aline Deschamps
Messages : 133
Enregistré le : 11 Mai 2010, 07:49
Contact :

Messagepar Aline Deschamps » 14 Déc 2010, 10:07

Bonjour,

Je ne maîtrise pas bien la fonction "assign()", mais si j'ai bien compris ce que vous cherchez à faire, pourquoi ne pas mettre quelquechose comme :

Code : Tout sélectionner

fonction1=function() {
  x=1
  y=x
  cat(paste("------ Fonction 1 : avant fonction 2 ------\nx=",x,"\n",sep=""))
  if (x==1) {y=function2(valeur=x)}
  x=y
  cat(paste("------ Fonction 1 : après function 2 ------\nx=",x,"\n",sep=""))
}

function2=function(valeur) {
  valeur=valeur+1
  cat(paste("------ Fonction 2 ------\nx=",valeur,"\n",sep=""))
  return valeur
}


Après je ne suis pas sûre que cela corresponde à ce que vous attendez...

Bonne continuation :)

A.D.

Maxime Hervé
Messages : 427
Enregistré le : 03 Mar 2010, 14:21
Contact :

Messagepar Maxime Hervé » 14 Déc 2010, 10:28

Merci Aline pour votre réponse, je me permets au passage cette simplification de votre code, le passage par une variable y étant inutile :

Code : Tout sélectionner

fonction1=function() {
  x=1
  cat(paste("------ Fonction 1 : avant fonction 2 ------\nx=",x,"\n",sep=""))
  if (x==1) {x=fonction2(valeur=x)}
  cat(paste("------ Fonction 1 : après function 2 ------\nx=",x,"\n",sep=""))
}

fonction2=function(valeur) {
  valeur=valeur+1
  cat(paste("------ Fonction 2 ------\nx=",valeur,"\n",sep=""))
  return(valeur)
}


Ceci dit mon petit exemple était trop simple, car bien qu'il fonctionne parfaitement avec votre solution il ne fonctionne plus si je veux faire la même chose avec plusieurs variables (donc plusieurs arguments pour la fonction 2). Un test simple ressemblerait à ça :

Code : Tout sélectionner

fonction1=function() {
  x1=1
  x2=1
  cat(paste("------ Fonction 1 : avant fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
  if (x1==1 & x2==1) {fonction2(valeur1=x1,valeur2=x2)}
  cat(paste("------ Fonction 1 : après fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
}

fonction2=function(valeur1,valeur2) {
  valeur1=valeur1+1
  valeur2=valeur2+2
  cat(paste("------ Fonction 2 ------\nx1=",valeur1,"\nx2=",valeur2,"\n",sep=""))
}


Cet exemple ne fonctionne pas puisque les variables x1 et x2 ne sont pas modifiées dans la fonction1. Et la solution via return() n'est pas envisageable puisque return() ne fonctionne pas avec plusieurs arguments...

Une autre idée :) ?

Aline Deschamps
Messages : 133
Enregistré le : 11 Mai 2010, 07:49
Contact :

Messagepar Aline Deschamps » 14 Déc 2010, 10:46

Ok si cela fonctionne comme ça, je n'avais pas testé et j'avais peur que R n'aime pas le "x=function(x)".

Sinon, l'élément return fonctionne avec les listes donc il est possible de l'utiliser et ensuite d'extraire tous les élements :

Code : Tout sélectionner

fonction1=function() {
  x1=1
  x2=1
  cat(paste("------ Fonction 1 : avant fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
  if (x1==1 & x2==1) {L=fonction2(valeur1=x1,valeur2=x2)}
  x1=L[[1]]
  x2=L[[2]]
  cat(paste("------ Fonction 1 : après fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
}

fonction2=function(valeur1,valeur2) {
  valeur1=valeur1+1
  valeur2=valeur2+2
  cat(paste("------ Fonction 2 ------\nx1=",valeur1,"\nx2=",valeur2,"\n",sep=""))
  return list(valeur1,valeur2)
}


Mais c'est peut-être un peu fastidieux si vous avez beaucoup de variables.

Bonne continuation :)

A.D.

Maxime Hervé
Messages : 427
Enregistré le : 03 Mar 2010, 14:21
Contact :

Messagepar Maxime Hervé » 14 Déc 2010, 11:00

Ok merci beaucoup, ça marche comme ça :) Juste 2 petites corrections si quelqu'un veut réutiliser le code :

Code : Tout sélectionner

fonction1=function() {
  x1=1
  x2=1
  cat(paste("------ Fonction 1 : avant fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
  if (x1==1 & x2==1) {
    L=fonction2(valeur1=x1,valeur2=x2)
    x1=L[[1]]
    x2=L[[2]]
  }
  cat(paste("------ Fonction 1 : après fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
}

fonction2=function(valeur1,valeur2) {
  valeur1=valeur1+1
  valeur2=valeur2+2
  cat(paste("------ Fonction 2 ------\nx1=",valeur1,"\nx2=",valeur2,"\n",sep=""))
  return(list(valeur1,valeur2))
}


Ceci dit par curiosité ou pour voir si c'est plus simple, peut-on faire la même chose simplement avec assign() , sans passer par une liste?

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Messagepar Logez Maxime » 14 Déc 2010, 13:14

Bonjour,

la seule petite difficulté avec la fonction assign est de savoir dans quel environnement tu vas stocké tes variables. Ici la fonction2 doit renvoyer les vecteurs x1 et x2 dans l'environnement de la fonction1 soit dans l'environnement supérieur :

Code : Tout sélectionner

fonction1 <- function() {
  x1 <- 1
  x2 <- 1
  cat(paste("------ Fonction 1 : avant fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
  if (x1==1 & x2==1) {
    fonction2(valeur1=x1,valeur2=x2)
  }
  cat(paste("------ Fonction 1 : après fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
}

fonction2 <- function(valeur1,valeur2) {
  valeur1 <- valeur1+1
  valeur2 <- valeur2+2
  cat(paste("------ Fonction 2 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
  assign("x1",valeur1, pos=parent.frame())
  assign("x2",valeur2, pos=parent.frame())
}


Maxime

Maxime Hervé
Messages : 427
Enregistré le : 03 Mar 2010, 14:21
Contact :

Messagepar Maxime Hervé » 14 Déc 2010, 13:24

Merci beaucoup Maxime, c'est effectivement ce que je cherchais à faire au début. J'avais essayé de donner un argument numérique à pos (sans succès), je ne connaissais pas parent.frame(). Il n'y aura aucune difficulté dans mon code à donner l'environnement, c'est toujours celui juste au-dessus.

Par curiosité, est-ce que l'on peut indiquer à l'argument pos directement un nom de fonction ?

Maxime

Edit : en fait je suis allé un peu vite, j'ai régulièrement besoin de remonter 2 environnement au-dessus. Du coup indiquer une fonction dans pos est indispensable...

Maxime Hervé
Messages : 427
Enregistré le : 03 Mar 2010, 14:21
Contact :

Messagepar Maxime Hervé » 14 Déc 2010, 16:18

Bon en fait j'ai trouvé, une fois que Maxime a donné le parent.frame() c'était pas bien compliqué...
Pour ceux que le code peut intéresser, je donne ce petit exemple avec 3 fonctions imbriquées :

Code : Tout sélectionner

fonction1=function() {
  x1=1
  x2=1
  cat(paste("------ Fonction 1 : avant fonctions 2 et 3 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
  if (x1==1 & x2==1) {fonction2(valeur1=x1,valeur2=x2)}
  cat(paste("------ Fonction 1 : après fonctions 2 et 3 ------\nx1=",x1,"\nx2=",x2,"\n",sep=""))
}

fonction2=function(valeur1,valeur2) {
  valeur1=valeur1+1
  valeur2=valeur2+2
  cat(paste("------ Fonction 2 ------\nx1=",valeur1,"\nx2=",valeur2,"\n",sep=""))
  fonction3(nombre1=valeur1,nombre2=valeur2)
}

fonction3=function(nombre1,nombre2) {
  nombre1=nombre1*3
  nombre2=nombre2*4
  cat(paste("------ Fonction 3 ------\nx1=",nombre1,"\nx2=",nombre2,"\n",sep=""))
  assign("x1",nombre1,pos=parent.frame(n=2))
  assign("x2",nombre2,pos=parent.frame(n=2))
}


Merci Aline et merci Maxime pour vos solutions !

Maxime

Aline Deschamps
Messages : 133
Enregistré le : 11 Mai 2010, 07:49
Contact :

Messagepar Aline Deschamps » 14 Déc 2010, 16:50

De rien ;)

En plus avec la solution de Maxime, j'aurais appris quelquechose qui peut être vraiment utile !

Bonne continuation,

A.D.


Retourner vers « Questions en cours »

Qui est en ligne

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