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

217

Lorsque 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'une seule ligne.

J'étudie maintenant pour un diplôme d'études supérieures et je dois écrire un projet dans MATLAB. Est-ce toujours une exigence 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 sont-elles accessibles depuis l'extérieur du fichier, ou uniquement la fonction qui porte le même nom que le fichier?

Remarque: j'utilise la version MATLAB R2007b.

Nathan Fellman
la source

Réponses:

271

La première fonction d'un fichier m (c'est-à-dire la fonction principale ) est invoquée lorsque ce fichier m est appelé. Il n'est pas nécessaire que la fonction principale ait le même nom que le fichier m, mais pour plus de clarté, elle devrait l'être . 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 m-fichier, appelées fonctions locales (ou "sous-fonctions" dans l'ancienne terminologie), ne peuvent être appelées que par la fonction principale et d'autres fonctions locales de ce m-fichier. Les fonctions d'autres m-fichiers ne peuvent pas les appeler. À partir de R2016b, vous pouvez également ajouter des fonctions locales aux scripts , bien que le comportement de portée soit toujours le même (c'est-à-dire qu'ils ne peuvent être appelés qu'à partir du script).

De plus, vous pouvez également déclarer des fonctions dans d' autres fonctions. Ces fonctions sont appelées fonctions imbriquées et 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 les fonctions dans lesquelles ils sont imbriqués, ce qui les rend très utiles bien que légèrement difficiles à utiliser.

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

Il existe certains moyens de contourner le comportement de portée de fonction normal décrit ci-dessus, tels que le passage de descripteurs de fonction comme arguments de sortie, comme mentionné dans les réponses de SCFrench et Jonas (qui, à partir de R2013b, est facilité par la localfunctionsfonction). Cependant, je ne suggérerais 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, disons que vous avez une fonction principale Adans un m-fichier A.m, ainsi que des fonctions locales D, Eet F. Maintenant que vous avez deux autres fonctions connexes Bet Cdans les fichiers m- B.met C.m, respectivement, que vous voulez aussi être en mesure d'appeler D, Eet F. Voici quelques options que vous avez:

  • Mettez D, Eet Fchacun dans leurs propres m-fichiers séparés, ce qui permet une autre fonction de les appeler. L'inconvénient est que la portée de ces fonctions est grande et ne se limite pas juste A, Bet C, mais le côté positif est que cela est assez simple.

  • Créez un defineMyFunctionsm-fichier (comme dans l'exemple de Jonas) avec D, Eet en Ftant que fonctions locales et une fonction principale qui leur renvoie simplement des descripteurs de fonction. Cela vous permet de conserver D, Eet Fdans le même fichier, mais cela ne fait rien en ce qui concerne la portée de ces fonctions car toute fonction qui peut appeler defineMyFunctionspeut les appeler. Vous devez également vous soucier de passer les poignées de fonction comme arguments pour vous assurer que vous les avez là où vous en avez besoin.

  • Copiez D, Eet Fdans B.met en C.mtant que fonctions locales. Cela limite la portée de leur utilisation juste A, Bet C, mais la mise à jour et la maintenance marques de votre code un cauchemar parce que vous avez trois exemplaires du même code dans des endroits différents.

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

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

Tout cela dépasse quelque peu la portée de votre question, et est probablement plus détaillé que vous n'en avez besoin, mais j'ai pensé qu'il pourrait être bon d'aborder le souci plus général d'organiser tous vos fichiers m. ;)

gnovice
la source
3
L'option de réponse préférée ressemble à ceci ^, @idigas
embert
1
@embert Je suppose qu'il voulait dire dans le sens de favoriser une question, qui peut être votée indépendamment du fait de favoriser.
OJFord
79

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 les descripteurs de fonctions aux fonctions locales, et un moyen pratique de le faire consiste à en faire des 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 il pourrait être utilisé:

>> myfuns = makefuns;
>> myfuns.fun1(5)    
ans =
     5
>> myfuns.fun2()     
ans =
     1
SCFrench
la source
36

La seule façon d'avoir plusieurs fonctions accessibles séparément dans un même fichier est de définir des MÉTHODES STATIQUES en utilisant une programmation orientée objet . Vous accéderiez à la fonction en tant que myClass.static1(), myClass.static2()etc.

La fonctionnalité OOP n'est officiellement prise en charge que depuis R2008a, donc à moins que vous ne vouliez utiliser l'ancienne syntaxe OOP non documentée, la réponse pour vous est non, comme expliqué par @gnovice .

ÉDITER

Une autre façon de définir plusieurs fonctions à l'intérieur d'un fichier qui sont accessibles de l'extérieur est de 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.

Jonas
la source
Je n'utiliserais pas oop à cet effet, cela ajoute un surcoût substantiel en particulier pour les méthodes statiques. ( stackoverflow.com/questions/1693429/… )
Daniel
1
@Daniel: La surcharge n'est perceptible que si vous effectuez une énorme quantité d'appels de fonction et que les calculs de la méthode sont quasi instantanés. Les deux conditions indiquent souvent une mauvaise conception - pas de vectorisation et des fonctions sans signification. Ainsi, je ne serais pas trop inquiet.
Jonas
23

J'aime vraiment la réponse de SCFrench - je voudrais souligner qu'elle peut facilement être modifiée pour importer les fonctions directement dans l'espace de travail en utilisant la fonction assignin. (Le faire comme ça me rappelle beaucoup la façon de faire des choses de Python "importer x de y")

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 puis utilisé ainsi:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1
Ru Hasha
la source
assignin('caller',...)serait plus correct. Vous souhaiterez peut-être utiliser ces fonctions à partir d'une autre fonction.
Cris Luengo
10

Dans le même sens que la réponse de SCFrench, mais avec un spin plus de style 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);     
SmallJoeMan
la source
4

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

source("mycode.m");

Je ne sais pas si cela est 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'.
JD
la source
3

Vous pouvez également regrouper des fonctions dans un fichier principal avec 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'

L'appel de subfun1 ressemblerait alors à ceci: str = main ('subfun1')

Thierry Dalon
la source
0

Depuis R2017b, cela n'est pas officiellement possible. La documentation pertinente indique que:

Les fichiers de programme peuvent contenir plusieurs fonctions. Si le fichier ne contient que des définitions de fonctions, la première fonction est la fonction principale et est la fonction que MATLAB associe au nom de 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 aboutir à quelque chose de similaire.

Diable
la source
Ce n'est pas exactement ce que Gnovice a déclaré au début de sa réponse?
Adiel
@Adiel Peut-être, mais plusieurs années s'étaient écoulées depuis cette réponse, et quelqu'un pourrait se demander si quelque chose avait changé.
Dev-iL
Je ne comprends toujours pas si quelque chose a changé ...? :)
Adiel
Nan. Autre que peut-être une documentation qui a été ajoutée pour aborder ce sujet spécifique.
Dev-iL
La raison pour laquelle j'ai écrit cette réponse est qu'il y a plusieurs versions, ils ont introduit des fonctions que vous pouvez ajouter à la fin des scripts - alors on peut se demander si quelque chose a également changé à cet égard (réponse: non).
Dev-iL
-1

J'ai essayé avec le SCFRench et avec le Ru Hasha en octave.

Et enfin ça marche: mais j'ai fait quelques modifications

function message = makefuns
    assignin('base','fun1', @fun1);   % Ru Hasha
    assignin('base', 'fun2', @fun2);  % Ru Hasha
    message.fun1=@fun1;               % SCFrench
    message.fun2=@fun2;               % SCFrench
end

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

function z=fun2
    z=1;
end

Peut être appelé dans un autre fichier 'm':

printf("%d\n", makefuns.fun1(123));
printf("%d\n", makefuns.fun2());

mettre à jour:

J'ai ajouté une réponse car ni le +72 ni le +20 ne fonctionnaient en octave pour moi. Celui que j'ai écrit fonctionne parfaitement (et je l'ai testé vendredi dernier lorsque j'ai écrit le post plus tard).

Gromph
la source
2
Si vous pouvez expliquer en quoi cela est différent des deux réponses existantes à partir desquelles vous copiez, je supprimerai mon downvote. Désolé de ne pas avoir commenté plus tôt. Je ne vois pas comment cela est différent, sauf que vous avez combiné les deux méthodes en une seule fonction et que vous faites donc quelque chose de redondant. Veuillez également insérer les liens appropriés vers les réponses auxquelles vous faites référence, "+72" et "+20" étant assez énigmatiques, il m'a fallu un certain temps pour réaliser que vous faites référence au décompte des voix, qui changera avec le temps et fera vos références inintelligible.
Cris Luengo