Ist es möglich, mehr als eine Funktion pro Datei in MATLAB zu definieren und von außerhalb dieser Datei darauf zuzugreifen?

216

Als ich für mein Grundstudium in EE studierte, verlangte MATLAB, dass jede Funktion in einer eigenen Datei definiert wurde, auch wenn es sich um einen Einzeiler handelte.

Ich studiere jetzt für einen Abschluss und muss ein Projekt in MATLAB schreiben. Ist dies noch eine Voraussetzung für neuere Versionen von MATLAB?

Gibt es Einschränkungen, wenn es möglich ist, mehr als eine Funktion in eine Datei einzufügen? Kann beispielsweise von außerhalb der Datei auf alle Funktionen in der Datei zugegriffen werden oder nur auf die Funktion, die denselben Namen wie die Datei hat?

Hinweis: Ich verwende MATLAB Release R2007b.

Nathan Fellman
quelle

Antworten:

270

Die erste Funktion in einer M-Datei (dh die Hauptfunktion ) wird aufgerufen, wenn diese M-Datei aufgerufen wird. Es ist nicht erforderlich, dass die Hauptfunktion denselben Namen wie die m-Datei hat, dies sollte jedoch aus Gründen der Übersichtlichkeit der Fall sein . Wenn sich Funktion und Dateiname unterscheiden, muss der Dateiname zum Aufrufen der Hauptfunktion verwendet werden.

Alle nachfolgenden Funktionen in der M-Datei, die als lokale Funktionen (oder "Unterfunktionen" in der älteren Terminologie) bezeichnet werden, können nur von der Hauptfunktion und anderen lokalen Funktionen in dieser M-Datei aufgerufen werden. Funktionen in anderen M-Dateien können sie nicht aufrufen. Ab R2016b können Sie Skripten auch lokale Funktionen hinzufügen , obwohl das Gültigkeitsbereichsverhalten immer noch dasselbe ist (dh sie können nur innerhalb des Skripts aufgerufen werden).

Darüber hinaus können Sie Funktionen auch innerhalb anderer Funktionen deklarieren . Diese werden als verschachtelte Funktionen bezeichnet und können nur innerhalb der Funktion aufgerufen werden, in der sie verschachtelt sind. Sie können auch auf Variablen in Funktionen zugreifen, in denen sie verschachtelt sind. Dies macht sie sehr nützlich, wenn auch etwas schwierig zu bearbeiten.

Mehr Denkanstöße ...

Es gibt einige Möglichkeiten, um das oben beschriebene normale Verhalten des Funktionsumfangs zu umgehen, z. B. das Übergeben von Funktionshandles als Ausgabeargumente, wie in den Antworten von SCFrench und Jonas erwähnt (was ab R2013b durch die localfunctionsFunktion erleichtert wird ). Ich würde jedoch nicht empfehlen, es sich zur Gewohnheit zu machen, auf solche Tricks zurückzugreifen, da es wahrscheinlich viel bessere Möglichkeiten gibt, Ihre Funktionen und Dateien zu organisieren.

Zum Beispiel, sagen wir , Sie eine Hauptfunktion Ain einer m-Datei A.m, zusammen mit lokalen Funktionen D, Eund F. Lassen Sie uns jetzt sagen , Sie haben zwei andere verwandte Funktionen Bund Cin m-Dateien B.mund C.mjeweils , dass Sie auch in der Lage sein nennen wollen D, Eund F. Hier sind einige Optionen, die Sie haben:

  • Setzen D, Eund Fjeder in einem eigenen m-Dateien, andere Funktion erlaubt , sie zu nennen. Der Nachteil ist , dass der Umfang dieser Funktionen groß ist und nicht nur beschränkt A, Bund C, aber der Vorteil ist , dass dies ganz einfach.

  • Erstellen Sie eine defineMyFunctionsm-Datei (wie in Jonas 'Beispiel) mit D, Eund Fals lokale Funktionen und einer Hauptfunktion, die einfach Funktionshandles an sie zurückgibt. Auf diese Weise können Sie und in derselben Datei behalten D, dies hat jedoch keine Auswirkungen auf den Umfang dieser Funktionen, da jede Funktion, die sie aufrufen kann, sie aufrufen kann. Sie müssen sich dann auch darum kümmern, die Funktionshandles als Argumente weiterzugeben, um sicherzustellen, dass Sie sie dort haben, wo Sie sie benötigen.EFdefineMyFunctions

  • Kopieren Sie D, Eund Fin B.mund C.mals lokale Funktionen. Dies beschränkt den Umfang ihrer Verwendung auf nur A, Bund Cmacht die Aktualisierung und Wartung Ihres Codes zu einem Albtraum, da Sie drei Kopien desselben Codes an verschiedenen Orten haben.

  • Verwenden Sie private Funktionen ! Wenn Sie A, Bund Cim gleichen Verzeichnis, können Sie ein Unterverzeichnis namens privateund Ort D, Eund Fdort, das jeweils als eine separate m-Datei. Dies schränkt dessen Umfang , so dass sie nur durch Funktionen im Verzeichnis unmittelbar über aufgerufen werden können (dh A, Bund C) und hält sie zusammen an der gleichen Stelle (aber immer noch verschiedene m-Dateien):

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

All dies geht etwas über den Rahmen Ihrer Frage hinaus und ist wahrscheinlich detaillierter als Sie es benötigen, aber ich dachte, es wäre gut, auf das allgemeinere Anliegen der Organisation all Ihrer M-Dateien einzugehen. ;)

gnovice
quelle
3
Die bevorzugte ^Antwortoption sieht so aus : @idigas
embert
1
@embert Ich nehme an, er meinte im Sinne der Bevorzugung einer Frage, die unabhängig von der Bevorzugung hochgestimmt werden kann.
OJFord
78

Im Allgemeinen lautet die Antwort auf Ihre Frage "Nein". Sie können nicht mehr als eine extern sichtbare Funktion pro Datei definieren. Sie können Funktionshandles jedoch an lokale Funktionen zurückgeben. Eine bequeme Möglichkeit besteht darin, sie zu Feldern einer Struktur zu machen. Hier ist ein Beispiel:

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

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

function z=fun2
  z=1;
end

Und so könnte es verwendet werden:

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

Die einzige Möglichkeit, mehrere separat zugängliche Funktionen in einer einzigen Datei zu haben, besteht darin, STATISCHE METHODEN mithilfe der objektorientierten Programmierung zu definieren . Sie würden die Funktion als Zugang myClass.static1(), myClass.static2()usw.

Die OOP-Funktionalität wird erst seit R2008a offiziell unterstützt. Wenn Sie also nicht die alte, nicht dokumentierte OOP-Syntax verwenden möchten, lautet die Antwort für Sie Nein, wie von @gnovice erläutert .

BEARBEITEN

Eine weitere Möglichkeit, mehrere Funktionen in einer Datei zu definieren, auf die von außen zugegriffen werden kann, besteht darin, eine Funktion zu erstellen, die mehrere Funktionshandles zurückgibt . Mit anderen Worten, Sie würden Ihre definierende Funktion als bezeichnen [fun1,fun2,fun3]=defineMyFunctions, wonach Sie out1=fun1(inputs)usw. verwenden könnten .

Jonas
quelle
Ich würde oop nicht für diesen Zweck verwenden, es fügt einen erheblichen Overhead hinzu, insbesondere für statische Methoden. ( stackoverflow.com/questions/1693429/… )
Daniel
1
@ Daniel: Der Overhead macht sich nur bemerkbar, wenn Sie eine große Anzahl von Funktionsaufrufen ausführen und die Berechnungen in der Methode quasi augenblicklich sind. Beide Bedingungen deuten oft auf ein schlechtes Design hin - keine Vektorisierung und bedeutungslose Funktionen. Somit wäre ich nicht zu besorgt.
Jonas
23

Die Antwort von SCFrench gefällt mir sehr gut - ich möchte darauf hinweisen, dass sie leicht geändert werden kann, um die Funktionen mithilfe der Zuweisungsfunktion direkt in den Arbeitsbereich zu importieren . (Wenn ich es so mache, erinnere ich mich sehr an Pythons "Import x from y" -Methode.)

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

Und dann so verwendet:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1
Ru Hasha
quelle
assignin('caller',...)wäre korrekter. Möglicherweise möchten Sie diese Funktionen in einer anderen Funktion verwenden.
Cris Luengo
10

In der gleichen Richtung wie die Antwort von SCFrench, jedoch mit einem C # -Stil.

Ich würde (und oft) eine Klasse erstellen, die mehrere statische Methoden enthält. Beispielsweise:

classdef Statistics

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

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

end

Da die Methoden statisch sind, müssen Sie die Klasse nicht instanziieren. Sie rufen die Funktionen wie folgt auf:

data = 1:10;

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

Ich definiere mit Octave mehrere Funktionen in einer .m-Datei und verwende dann den Befehl aus der .m-Datei, in der ich die Funktionen aus dieser Datei verwenden muss:

source("mycode.m");

Ich bin mir nicht sicher, ob dies mit Matlab verfügbar ist.

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
quelle
3

Sie können Funktionen auch in einer Hauptdatei zusammen mit der Hauptfunktion gruppieren, die folgendermaßen aussieht:

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

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

Dann würde der Aufruf von subfun1 folgendermaßen aussehen: str = main ('subfun1')

Thierry Dalon
quelle
0

Ab R2017b ist dies offiziell nicht möglich. In der entsprechenden Dokumentation heißt es:

Programmdateien können mehrere Funktionen enthalten. Wenn die Datei nur Funktionsdefinitionen enthält, ist die erste Funktion die Hauptfunktion und die Funktion, die MATLAB dem Dateinamen zuordnet. Funktionen, die der Hauptfunktion oder dem Skriptcode folgen, werden als lokale Funktionen bezeichnet. Lokale Funktionen sind nur in der Datei verfügbar.

In anderen Antworten vorgeschlagene Problemumgehungen können jedoch zu ähnlichen Ergebnissen führen.

Teufel
quelle
Dies ist nicht genau das, was Gnovice zu Beginn seiner Antwort gesagt hat?
Adiel
@Adiel Vielleicht, aber seit dieser Antwort waren mehrere Jahre vergangen, und jemand könnte sich fragen, ob sich etwas geändert hat.
Dev-iL
Ich habe immer noch nicht verstanden, ob sich etwas geändert hat ...? :)
Adiel
Nee. Abgesehen von möglicherweise einer Dokumentation, die hinzugefügt wurde, um dieses spezielle Thema zu behandeln.
Dev-iL
Der Grund, warum ich diese Antwort geschrieben habe, ist, dass sie vor einigen Releases Funktionen eingeführt haben , die Sie am Ende von Skripten hinzufügen können. Man könnte sich also fragen, ob sich auch diesbezüglich etwas geändert hat (Antwort: Nein).
Dev-iL
-1

Ich habe es mit dem SCFRench und mit dem Ru Hasha auf Oktave versucht .

Und schließlich funktioniert es: aber ich habe einige Änderungen vorgenommen

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

Kann in einer anderen 'm'-Datei aufgerufen werden:

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

aktualisieren:

Ich habe eine Antwort hinzugefügt, da weder die +72 noch die +20 für mich in Oktave arbeiteten . Der, den ich geschrieben habe, funktioniert perfekt (und ich habe ihn letzten Freitag getestet, als ich später den Beitrag schrieb).

Gromph
quelle
2
Wenn Sie erklären können, wie sich dies von den beiden vorhandenen Antworten unterscheidet, aus denen Sie kopieren, werde ich meine Ablehnung entfernen. Entschuldigung, dass Sie nicht früher kommentiert haben. Ich sehe nur nicht, wie das anders ist, außer dass Sie beide Methoden in einer Funktion kombiniert haben und daher etwas Redundantes tun. Fügen Sie außerdem die richtigen Links zu den Antworten ein, auf die Sie verweisen. "+72" und "+20" sind ziemlich kryptisch. Es hat eine Weile gedauert, bis mir klar wurde, dass Sie sich auf die Stimmenzahlen beziehen, die sich im Laufe der Zeit ändern und Ihre Referenzen erstellen unverständlich.
Cris Luengo