È possibile definire più di una funzione per file in MATLAB e accedervi dall'esterno di quel file?


217

Quando studiavo per il mio corso di laurea in EE, MATLAB richiedeva che ogni funzione fosse definita in un suo file, anche se era una linea.

Ora sto studiando per una laurea e devo scrivere un progetto in MATLAB. È ancora un requisito per le versioni più recenti di MATLAB?

Se è possibile inserire più di una funzione in un file, ci sono delle restrizioni? Ad esempio, è possibile accedere a tutte le funzioni nel file dall'esterno del file o solo la funzione che ha lo stesso nome del file?

Nota: sto utilizzando MATLAB versione R2007b.

Risposte:


271

La prima funzione in un file m (cioè la funzione principale ), viene invocata quando viene chiamato quel file m. Non è necessario che la funzione principale abbia lo stesso nome del file m, ma per chiarezza dovrebbe . Quando la funzione e il nome del file differiscono, è necessario utilizzare il nome del file per chiamare la funzione principale.

Tutte le funzioni successive nel file m, chiamate funzioni locali (o " funzioni secondarie" nella terminologia precedente), possono essere chiamate solo dalla funzione principale e da altre funzioni locali in quel file m. Le funzioni in altri file m non possono chiamarle. A partire da R2016b, è possibile aggiungere anche funzioni locali agli script , sebbene il comportamento dell'ambito sia sempre lo stesso (ovvero possono essere richiamati solo all'interno dello script).

Inoltre, è anche possibile dichiarare funzioni all'interno di altre funzioni. Queste sono chiamate funzioni nidificate e possono essere chiamate solo all'interno della funzione in cui sono nidificate. Possono anche avere accesso a variabili nelle funzioni in cui sono nidificati, il che le rende abbastanza utili seppur leggermente complicate con cui lavorare.

Più spunti di riflessione ...

Esistono alcuni modi per aggirare il normale comportamento dell'ambito delle funzioni descritto sopra, come passare gli handle di funzione come argomenti di output come menzionato nelle risposte di SCFrench e Jonas (che, a partire da R2013b, è facilitato dalla localfunctionsfunzione). Tuttavia, non consiglierei di prendere l'abitudine di ricorrere a tali trucchi, poiché probabilmente ci sono opzioni molto migliori per organizzare le tue funzioni e i tuoi file.

Ad esempio, supponiamo che tu abbia una funzione principale Ain un file m A.m, insieme alle funzioni localiD , Ee F. Ora diciamo che si dispone di altre due funzioni correlate Be Cin m-file B.me C.m, rispettivamente, che si vuole anche essere in grado di chiamare D, Ee F. Ecco alcune opzioni che hai:

  • Inserisci D, Ee Fciascuno nei propri m-file separati, consentendo a qualsiasi altra funzione di chiamarli. Il lato negativo è che la portata di queste funzioni è grande e non è limitato al solo A, Be C, ma il lato positivo è che questo è abbastanza semplice.

  • Creare un defineMyFunctions M-file (come nell'esempio di Jonas') con D, Ee Fcome funzioni locali e una funzione principale che semplicemente restituisce funzione gestisce a loro. Ciò consente di conservare D, Ee Fnello stesso file, ma non fa nulla per quanto riguarda l'ambito di queste funzioni poiché qualsiasi funzione che può chiamare defineMyFunctionspuò invocarle. Inoltre, devi preoccuparti di passare gli handle di funzione come argomenti per assicurarti di averli dove ti servono.

  • Copia D,E e Fin B.me C.mcome funzioni locali. Questo limita la portata del loro utilizzo a poco A, Be C, ma rende l'aggiornamento e la manutenzione del codice un incubo perché avete tre copie dello stesso codice in luoghi diversi.

  • Usa le funzioni private ! Se si dispone A, Be Cnella stessa directory, è possibile creare una sottodirectory chiamata privatee luogo D, EeF lì dentro, ciascuno come un m-file separato. Questo limita il campo di applicazione in modo che possano essere chiamati solo da funzioni nella directory immediatamente sopra (vale a dire A, Be C) e li tiene insieme nello stesso luogo (ma ancora diverse m-files):

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

Tutto questo va un po 'al di fuori dell'ambito della tua domanda, ed è probabilmente più dettagliato di quello che ti serve, ma ho pensato che potrebbe essere utile toccare la preoccupazione più generale di organizzare tutti i tuoi file m. ;)


3
L'opzione di risposta preferita è simile a questa ^, @idigas
embert

1
@embert presumo che intendesse sulla falsariga di una domanda, che può essere votata in modo indipendente indipendentemente dalla preferenza.
OJFord,

79

Generalmente, la risposta alla tua domanda è no, non puoi definire più di una funzione visibile esternamente per file. Tuttavia, è possibile restituire gli handle di funzione alle funzioni locali e un modo conveniente per farlo è renderli campi di una struttura. Ecco un esempio:

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

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

function z=fun2
  z=1;
end

Ed ecco come potrebbe essere usato:

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

36

L'unico modo per avere più funzioni accessibili separatamente in un singolo file è definire METODI STATICI usando la programmazione orientata agli oggetti . Avresti accesso alla funzione come myClass.static1(), myClass.static2()ecc.

La funzionalità OOP è ufficialmente supportata solo da R2008a, quindi a meno che non si desideri utilizzare la vecchia sintassi OOP non documentata, la risposta è no, come spiegato da @gnovice .

MODIFICARE

Un altro modo per definire più funzioni all'interno di un file accessibili dall'esterno è quello di creare una funzione che restituisca più handle . In altre parole, chiamereste la vostra funzione di definizione come [fun1,fun2,fun3]=defineMyFunctions, dopo di che potreste usare out1=fun1(inputs)ecc.


Non userei oop per questo scopo, aggiunge un notevole sovraccarico soprattutto per i metodi statici. ( stackoverflow.com/questions/1693429/… )
Daniel

1
@Daniel: l'overhead è evidente solo se si eseguono molte chiamate di funzione e i calcoli nel metodo sono quasi istantanei. Entrambe le condizioni spesso indicano un cattivo design: nessuna vettorializzazione e funzioni insignificanti. Quindi, non sarei troppo preoccupato.
Jonas,

23

Mi piace molto la risposta di SCFrench - Vorrei sottolineare che può essere facilmente modificato per importare le funzioni direttamente nell'area di lavoro utilizzando la funzione di assegnazione. (Farlo in questo modo mi ricorda molto il modo "import x da y" di Python di fare le cose)

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

E quindi usato così:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1

assignin('caller',...)sarebbe più corretto. È possibile che si desideri utilizzare queste funzioni da un'altra funzione.
Cris Luengo,

10

Sulla stessa linea della risposta di SCFrench, ma con uno spin più stile C #.

Vorrei (e spesso faccio) una classe contenente più metodi statici. Per esempio:

classdef Statistics

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

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

end

Poiché i metodi sono statici, non è necessario installare la classe. Le funzioni vengono chiamate come segue:

data = 1:10;

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

4

Definisco più funzioni in un file .m con Octave e quindi uso il comando dal file .m dove devo usare le funzioni di quel file:

source("mycode.m");

Non sono sicuro se questo è disponibile con 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'.

3

Puoi anche raggruppare le funzioni in un file principale insieme alla funzione principale in questo modo:

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

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

Quindi chiamare subfun1 sarebbe simile al seguente: str = main ('subfun1')


0

A partire da R2017b, questo non è ufficialmente possibile. La documentazione pertinente afferma che:

I file di programma possono contenere più funzioni. Se il file contiene solo definizioni di funzione, la prima funzione è la funzione principale ed è la funzione che MATLAB associa al nome del file. Le funzioni che seguono la funzione principale o il codice di script sono chiamate funzioni locali. Le funzioni locali sono disponibili solo all'interno del file.

Tuttavia, soluzioni alternative suggerite in altre risposte possono ottenere qualcosa di simile.


Questo non è esattamente ciò che Gnovice ha dichiarato all'inizio della sua risposta?
Adiel,

@Adiel Forse, ma erano passati diversi anni da quella risposta, e qualcuno potrebbe chiedersi se qualcosa è cambiato.
Dev-iL,

Non ho ancora capito se qualcosa è cambiato ...? :)
Adiel,

No. Altro che forse della documentazione che è stata aggiunta per affrontare questo argomento specifico.
Dev-iL,

Il motivo per cui ho scritto questa risposta è perché diverse versioni fa hanno introdotto funzioni che è possibile aggiungere alla fine degli script , quindi ci si potrebbe chiedere se qualcosa è cambiato anche in questo senso (risposta: no).
Dev-iL,

-1

Ho provato con lo SCFRench e con il Ru Hasha all'ottava.

E infine funziona: ma ho apportato alcune modifiche

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

Può essere chiamato in un altro file 'm':

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

aggiornare:

Ho aggiunto una risposta perché il +72 né il +20 hanno funzionato in ottava per me. Quello che ho scritto funziona perfettamente (e l'ho provato venerdì scorso quando in seguito ho scritto il post).


2
Se riesci a spiegare in che modo differisce dalle due risposte esistenti da cui stai copiando, rimuoverò il mio voto negativo. Ci scusiamo per non aver commentato prima. Non vedo come sia diverso, tranne per il fatto che hai combinato entrambi i metodi in un'unica funzione e quindi stai facendo qualcosa di ridondante. Inoltre, si prega di inserire collegamenti adeguati alle risposte a cui si fa riferimento, "+72" e "+20" sono piuttosto enigmatici, mi ci è voluto un po 'di tempo per rendermi conto che ti riferisci al conteggio dei voti, che cambierà nel tempo e farà i tuoi riferimenti incomprensibile.
Cris Luengo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.