web-dev-qa-db-fra.com

Est-il possible de définir plus d'une fonction par fichier dans MATLAB et d'y accéder de l'extérieur?

Quand j'étudiais pour mon diplôme de premier cycle en EE, MATLAB exigeait que chaque fonction soit définie dans son propre fichier, même s'il s'agissait d'un one-liner.

J'étudie maintenant pour un diplôme d'études supérieures et je dois écrire un projet dans MATLAB. Est-ce toujours nécessaire pour les nouvelles versions de MATLAB?

S'il est possible de mettre plus d'une fonction dans un fichier, y a-t-il des restrictions à cela? Par exemple, toutes les fonctions du fichier peuvent-elles être accédées de l'extérieur du fichier ou uniquement la fonction qui porte le même nom que le fichier?

Remarque: j'utilise la version R2007b de MATLAB.

203
Nathan Fellman

La première fonction dans un fichier m (c'est-à-dire fonction principale ) est invoquée lorsque ce fichier m est appelé. Il n'est pas requis que la fonction principale porte le même nom que le fichier m, mais pour des raisons de clarté, elle devrait . Lorsque la fonction et le nom de fichier diffèrent, le nom de fichier doit être utilisé pour appeler la fonction principale.

Toutes les fonctions suivantes du fichier m, appelées fonctions locales (ou "sous-fonctions" dans l'ancienne terminologie), ne peuvent être appelées que par la fonction principale et les autres fonctions locales de ce fichier m. Les fonctions dans d'autres fichiers m ne peuvent pas les appeler. À partir de la R2016b, vous pouvez ajouter des fonctions locales aux scripts également, bien que le comportement de la portée soit toujours le même (c'est-à-dire qu'ils ne peuvent être appelés qu'à partir du script).

En outre, vous pouvez également déclarer des fonctions au sein de autres fonctions. Celles-ci s'appellent fonctions imbriquées , et elles ne peuvent être appelées qu'à partir de la fonction dans laquelle elles sont imbriquées. Ils peuvent également avoir accès à des variables dans des fonctions dans lesquelles elles sont imbriquées, ce qui les rend très utiles, bien que légèrement délicates à utiliser.

Plus de matière à réflexion ...

Il existe certaines manières de contourner le comportement normal de la portée de la fonction décrit ci-dessus, telles que le passage de descripteurs de fonction comme arguments de sortie, comme indiqué dans les réponses de SCFrench et Jonas = (qui, à partir de R2013b, est facilité par la fonction localfunctions ). Cependant, je ne conseillerais pas de prendre l'habitude de recourir à de telles astuces, car il existe probablement de bien meilleures options pour organiser vos fonctions et vos fichiers.

Par exemple, supposons que vous ayez une fonction principale A dans un fichier m A.m, ainsi que des fonctions locales D, E et F. Supposons maintenant que vous ayez deux autres fonctions connexes B et C dans m-files B.m et C.m, respectivement, que vous souhaitez également pouvoir appeler D, E et F. Voici quelques options que vous avez:

  • Placez D, E et F dans leurs propres fichiers m distincts, permettant ainsi à toute autre fonction de les appeler. L'inconvénient est que l'étendue de ces fonctions est vaste et n'est pas limitée à A, B et C, mais l'inconvénient est que c'est assez simple.

  • Créez un m-fichier defineMyFunctions (comme dans l'exemple de Jonas) avec D, E et F comme fonctions locales et une fonction principale qui leur renvoie simplement des descripteurs de fonctions. Cela vous permet de conserver D, E et F dans le même fichier, mais cela ne fait rien quant à la portée de ces fonctions car toute fonction pouvant appeler defineMyFunctions peut les appeler. Ensuite, vous devez également vous soucier de transmettre les descripteurs de fonction sous forme d'arguments pour vous assurer que vous les avez où vous en avez besoin.

  • Copiez D, E et F dans B.m et C.m en tant que fonctions locales. Cela limite leur utilisation à seulement A, B et C, mais fait de la mise à jour et de la maintenance de votre code un cauchemar, car vous disposez de trois copies du même code à des endroits différents.

  • Utilisez fonctions privées ! Si vous avez A, B et C dans le même répertoire, vous pouvez créer un sous-répertoire appelé private. et placez D, E et F dedans, chacun dans un fichier m séparé. Cela limite leur portée, de sorte qu'elles ne peuvent être appelées que par les fonctions du répertoire immédiatement supérieur (c'est-à-dire A, B et C) et les garde ensemble au même endroit (mais des fichiers m différents toujours):

    myDirectory/
        A.m
        B.m
        C.m
        private/
            D.m
            E.m
            F.m
    

Tout cela dépasse un peu le cadre de votre question et contient probablement plus de détails que nécessaire, mais j’ai pensé qu’il serait peut-être bon de parler de la préoccupation plus générale de l’organisation de tous vos fichiers m. ;)

263
gnovice

Généralement, la réponse à votre question est non, vous ne pouvez pas définir plus d'une fonction visible de l'extérieur par fichier. Vous pouvez cependant renvoyer des descripteurs de fonction à des fonctions locales, ce qui constitue un moyen pratique de les transformer en champs d'une structure. Voici un exemple:

function funs = makefuns
  funs.fun1=@fun1;
  funs.fun2=@fun2;
end

function y=fun1(x)
  y=x;
end

function z=fun2
  z=1;
end

Et voici comment cela pourrait être utilisé:

>> myfuns = makefuns;
>> myfuns.fun1(5)    
ans =
     5
>> myfuns.fun2()     
ans =
     1
76
SCFrench

Le seul moyen d'avoir plusieurs fonctions accessibles séparément dans un même fichier est de définir STATIC METHODS à l'aide de programmation orientée objet . Vous accéderiez à la fonction en tant que myClass.static1(), myClass.static2() etc.

La fonctionnalité POO n'est prise en charge officiellement que depuis la version R2008a. Par conséquent, à moins d'utiliser l'ancienne syntaxe non documentée OOP, la réponse est non, comme l'explique @ gnovice .

EDIT

Une autre façon de définir plusieurs fonctions à l'intérieur d'un fichier accessible de l'extérieur consiste à créer une fonction qui renvoie plusieurs descripteurs de fonction . En d’autres termes, vous appelleriez votre fonction de définition comme [fun1,fun2,fun3]=defineMyFunctions, après quoi vous pourriez utiliser out1=fun1(inputs) etc.

36
Jonas

J'aime beaucoup la réponse de SCFrench - je voudrais souligner qu'elle peut être facilement modifiée pour importer les fonctions directement dans l'espace de travail à l'aide de la fonction assignin. (Cela me rappelle beaucoup la manière de faire les choses "import x de y" de Python)

function message = makefuns
  assignin('base','fun1',@fun1);
  assignin('base','fun2',@fun2);
  message='Done importing functions to workspace';
end

function y=fun1(x)
  y=x;
end

function z=fun2
  z=1;
end

Et ensuite utilisé ainsi:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1
23
Ru Hasha

Dans le même sens que la réponse de SCFrench, mais avec un style plus C #.

Je voudrais (et fais souvent) une classe contenant plusieurs méthodes statiques. Par exemple:

classdef Statistics

    methods(Static)
        function val = MyMean(data)
            val = mean(data);
        end

        function val = MyStd(data)
            val = std(data);
        end
    end

end

Comme les méthodes sont statiques, vous n'avez pas besoin d'instancier la classe. Vous appelez les fonctions comme suit:

data = 1:10;

mean = Statistics.MyMean(data);
std = Statistics.MyStd(data);     
9
SmallJoeMan

Je définis plusieurs fonctions dans un fichier .m avec Octave, puis j'utilise la commande du fichier .m où je dois utiliser les fonctions de ce fichier:

source("mycode.m");

Pas sûr que ce soit disponible avec Matlab.

octave:8> help source
'source' is a built-in function

 -- Built-in Function:  source (FILE)
     Parse and execute the contents of FILE.  This is equivalent to
     executing commands from a script file, but without requiring the
     file to be named `FILE.m'.
4
J.D.

Vous pouvez également regrouper les fonctions dans un fichier principal, la fonction principale ressemblant à ceci:

function [varargout] = main( subfun, varargin )
[varargout{1:nargout}] = feval( subfun, varargin{:} ); 

% paste your subfunctions below ....
function str=subfun1
str='hello'

Ensuite, appeler subfun1 ressemblerait à ceci: str = main ('subfun1')

3
Thierry Dalon

À partir de R2017b, ceci n'est pas officiellement possible. Le documentation pertinente indique que:

Les fichiers de programme peuvent contenir plusieurs fonctions. Si le fichier ne contient que des définitions de fonction, la première fonction est la fonction principale et correspond à la fonction que MATLAB associe au nom du fichier. Les fonctions qui suivent la fonction principale ou le code de script sont appelées fonctions locales. Les fonctions locales ne sont disponibles que dans le fichier.

Cependant, les solutions de contournement suggérées dans d'autres réponses peuvent permettre d'obtenir quelque chose de similaire.

0
Dev-iL