4 votes

Utilisation d'une fonction avec des paramètres d'entrée facultatifs

Je me débats avec ce problème depuis environ une semaine. J'ai essayé de convertir un script en une fonction à des fins de recherche. Le problème est que le code a beaucoup d'instructions conditionnelles existantes pour les variables, donc certaines variables n'existeront pas dans l'espace de travail lorsqu'elles seront vérifiées (c'est pourquoi il fonctionne bien en tant que script).

Varargin n'est pas une solution à ce problème car certaines des fonctions INPUTS n'existeront pas.

Espace de travail

var1 = 1
var2 = 2
var4 = 4

Code à transformer en fonction

if exist('var3','var')
   disp('var 3 exists')
else
   disp('var 3 does not exist')
end

La fonction suivante ne fonctionnera PAS car elle appelle la variable 3 qui n'existe pas.

fonction d'appel

runCode(var1, var2, var3, var4)

A l'origine, j'ai écrit ceci avant ma fonction et j'ai fait en sorte que le code vérifie pour isnan au lieu de exist mais ce n'est pas une bonne pratique et comme la fonction est appelée souvent, je ne veux pas avoir à mettre à jour la configuration de cette fonction chaque fois que des modifications sont apportées au code.

  if ~exist("var1", "var"), var1= NaN; end 
  if ~exist("var2", "var"), var2= NaN; end 
  if ~exist("var3", "var"), var3= NaN; end 
  if ~exist("var4", "var"), var4= NaN; end 

Je ne veux pas utiliser eval Le chargement de l'espace de travail m'a posé des problèmes parce qu'un grand nombre de chiffres sont présents et que cela perturbe le comptage des chiffres dans une partie ultérieure du code. Les seules idées que j'ai pour l'instant sont d'avoir une configuration script pour les déclarations if précédentes, ou d'enregistrer d'une manière ou d'une autre toutes les données de l'espace de travail dans une structure ou quelque chose comme ça, puis d'assigner les valeurs à l'espace de travail correspondant. who chaîne de caractères (donne les noms des variables de l'espace de travail).

Merci pour toutes les idées que vous pourriez avoir

4voto

Cris Luengo Points 22016

Le script actuel se comporte différemment selon l'existence d'un ensemble de variables aux noms prédéfinis. Ceci est difficile à reproduire dans une fonction, car une fonction devrait ne pas lire les valeurs de l'espace de travail appelant. Il est bien sûr possible de le faire :

try
   var1 = evalin('caller','var1');
catch
   % do nothing, the variable doesn't exist in the caller, it won't exist here
end

Mais cette vraiment mauvaise pratique, et pas différente d'un script. Et le PO a spécifiquement dit qu'il ne voulait pas utiliser eval .

Il existe une alternative, que j'hésite à recommander car elle est presque aussi mauvaise que la précédente. Nous allons définir une fonction dont les arguments d'entrée ne sont pas basés sur l'ordre, mais sur le nom :

runCode(var1)

se comportera différemment de

runCode(var2)

Mais les deux déclarations suivantes se comporteront de manière identique :

runCode(var1,var2)
runCode(var2,var1)

Dégoûtée ? Vous devriez l'être !

L'astuce consiste à utiliser inputname comme suit :

function runCode(varargin)
for ii = 1:nargin
   switch inputname(ii)
      case 'var1', var1 = varargin{ii};
      case 'var2', var2 = varargin{ii};
      case 'var3', var3 = varargin{ii};
      case 'var4', var4 = varargin{ii};
      otherwise,   error('Illegal input argument')
   end
end

Le reste de la fonction serait le corps du script de OP, qui contient le code suivant :

if exist('var1','var')
   % ...
end

C'est-à-dire que nous voyons d'abord quelles variables sont passées à la fonction, puis nous voyons quelles variables existent. Il devrait être possible de réécrire le script lui-même pour remplacer la fonction exist vérifie avec des recherches dans une liste de noms d'arguments d'entrée.

2voto

matlabgui Points 4861

Vous pourriez faire en sorte que les entrées soient dans des paires d'arg, donc vous l'appelez comme ça :

runCode ( 'var1', 123, 'var2', 456, 'var4', 789)

Où se trouve votre fonction

function runCode ( varargin )
  defaults.var1 =[];
  defaults.var2 =[];
  defaults.var3 =[];
  defaults.var4 =[];

  for ii = 1:2:nargin
    if isfield ( defaults, varargin{ii} )
      defaults.(varargin{ii}) = varargin{ii+1};
    else
      Throw error?
    end

Ensuite, vous modifiez la vérification de la var3 pour vérifier si la valeur defaults.var3 est vide.

0voto

Daniel me Points 89

Merci pour tous les commentaires. Étant donné que la fonction que je veux appeler est parfois appelée au même endroit mais avec des variables différentes, je ne peux pas modifier la configuration des paramètres. Donc, ce que j'ai fait pourrait vous faire pleurer mais j'ai un setup script que j'appelle avant la fonction qui vérifie si les paramètres existent ou non, et les met à un NaN si ce n'est pas le cas. C'est exactement la même solution que j'avais avant mais dans un script.

PS Je suis d'accord pour que cela reste un script mais ils veulent vraiment que ce soit une fonction ¯_()_/¯.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X