Czy można zdefiniować więcej niż jedną funkcję na plik w Matlabie i uzyskać do nich dostęp spoza tego pliku?

Kiedy studiowałem na studiach licencjackich w EE, MATLAB wymagał zdefiniowania każdej funkcji w swoim własnym pliku, nawet jeśli była to jednoliniowa.

Uczę się teraz na studia podyplomowe i muszę napisać projekt w MATLAB. Czy jest to nadal wymóg dla nowszych wersji MATLAB?

Jeśli możliwe jest umieszczenie więcej niż jednej funkcji w pliku, czy są jakieś ograniczenia? Na przykład, czy wszystkie funkcje w pliku mogą być dostępne z zewnątrz plik, czy tylko funkcja o tej samej nazwie co plik?

Uwaga: używam MATLAB release R2007b.

Author: gnovice, 2010-08-25

9 answers

Pierwsza funkcja w pliku m (tj. główna funkcja ), jest wywoływana, gdy ten plik M jest wywoływany. Nie jest wymagane aby główna funkcja miała taką samą nazwę jak plik m, ale dla jasności powinna . Gdy funkcja i nazwa pliku różnią się, nazwa pliku musi być użyta do wywołania głównej funkcji.

Wszystkie kolejne funkcje w pliku m, nazywane local functions (lub "subfunctions" w starszej terminologii), mogą być wywoływane przez główną funkcję i inne lokalne funkcje w tym m-pliku. Funkcje w innych plikach m nie mogą ich wywołać. Począwszy od R2016b, możesz dodać lokalne funkcje do skryptów , chociaż zachowanie zakresu jest nadal takie samo (tzn. mogą być wywoływane tylko ze skryptu).

Dodatkowo Można zadeklarować funkcje wewnątrz innych funkcji. Są one nazywane funkcjami zagnieżdżonymi i mogą być wywoływane tylko z poziomu funkcji, którą są zagnieżdżone. Mogą również mieć dostęp do zmiennych w funkcjach, w których są zagnieżdżone, co czyni je bardzo przydatnymi, choć nieco trudnymi do pracy.

Więcej do przemyślenia...

Istnieją pewne sposoby obejścia normalnego zachowania zakresu funkcji opisanego powyżej, takie jak przekazywanie funkcji obsługujejako argumentów wyjściowych, jak wspomniano w odpowiedziach z SCFrenchi Jonas (co, począwszy od r2013b, jest ułatwione przez localfunctions funkcja). Nie sugerowałbym jednak przyzwyczajania się do takich sztuczek, ponieważ prawdopodobnie istnieją znacznie lepsze opcje organizowania funkcji i plików.

Na przykład, załóżmy, że masz główną funkcję A w pliku m A.m, wraz z funkcjami lokalnymi D, E, i F. Załóżmy, że masz dwie inne powiązane funkcje B i C odpowiednio w plikach m B.m i C.m, które również chcesz wywołać D, E, i F. Oto kilka opcji, które masz:

  • Put D, E, i F każdy w osobnych plikach m, pozwalając na wywołanie dowolnej innej funkcji. Minusem jest to, że zakres tych funkcji jest duży i nie ogranicza się tylko do A, B, i C, ale plusem jest to, że jest to dość proste.

  • Utwórz defineMyFunctions M-Plik (jak w przykładzie Jonasa) z D, E, and F as local functions and a main function that simply returns function handles za nich. Pozwala to zachować D, E, i F w tym samym pliku, ale nie robi nic w odniesieniu do zakresu tych funkcji, ponieważ każda funkcja, która może wywołać defineMyFunctions może je wywołać. Musisz również martwić się o przekazywanie uchwytów funkcji jako argumentów, aby upewnić się, że masz je tam, gdzie ich potrzebujesz.

  • Kopiuj D, E i F na B.m i C.m jako funkcje Lokalne. Ogranicza to zakres ich wykorzystania do A, B, i C, ale sprawia, że aktualizacja i konserwacja kodu jest koszmarem, ponieważ masz trzy kopie tego samego kodu w różnych miejscach.

  • Użyj funkcji prywatnych ! Jeśli masz A, B, i C w tym samym katalogu możesz utworzyć podkatalog o nazwie private i umieścić D, E, i F tam, każdy jako osobny plik M. To ogranicza ich zakres, więc mogą być wywoływane tylko przez funkcje w katalogu bezpośrednio powyżej (tj. A, B, oraz C) i trzyma je razem w tym samym miejscu (ale wciąż inne pliki m):

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

Wszystko to wykracza nieco poza zakres twojego pytania i jest prawdopodobnie bardziej szczegółowe niż potrzebujesz, ale pomyślałem, że dobrze byłoby poruszyć bardziej ogólną troskę o organizację wszystkich Twoich plików M. ;)

 278
Author: gnovice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-13 20:06:51

Ogólnie rzecz biorąc, odpowiedź na twoje pytanie brzmi Nie, Nie można zdefiniować więcej niż jednej funkcji widocznej na zewnątrz na plik. Możesz jednak zwrócić uchwyty funkcji do funkcji lokalnych, a wygodnym sposobem na to jest uczynienie z nich pól struktury. Oto przykład:

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

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

function z=fun2
  z=1;
end

A oto jak można go użyć:

>> myfuns = makefuns;
>> myfuns.fun1(5)    
ans =
     5
>> myfuns.fun2()     
ans =
     1
 81
Author: SCFrench,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-26 01:15:12

Jedynym sposobem na posiadanie wielu, oddzielnie dostępnych funkcji w jednym pliku jest zdefiniowanie statycznych metod za pomocą programowania obiektowego. Można uzyskać dostęp do funkcji jako myClass.static1(), myClass.static2() itd.

Funkcjonalność OOP jest oficjalnie obsługiwana tylko od R2008a, więc jeśli nie chcesz używać starej, nieudokumentowanej składni OOP, odpowiedź dla ciebie brzmi nie, jak wyjaśniono przez @gnovice .

EDIT

Jeszcze jeden sposób definiowania wielu funkcji wewnątrz pliku, który jest dostępny z zewnątrz jest utworzenie funkcji, która zwraca wiele uchwytów funkcji . Innymi słowy, można nazwać funkcję definiującą [fun1,fun2,fun3]=defineMyFunctions, po czym można użyć out1=fun1(inputs) itd.

 38
Author: Jonas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:10

Bardzo podoba mi się odpowiedź SCFrench - chciałbym zwrócić uwagę, że można ją łatwo zmodyfikować, aby zaimportować funkcje bezpośrednio do obszaru roboczego za pomocą funkcji assignin. (Robienie tego w ten sposób przypomina mi wiele sposobów "importowania x Z y" w Pythonie)

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

A następnie użyty w ten sposób:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1
 24
Author: Ru Hasha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-01 06:59:54

Podobnie jak odpowiedź Scfrencha, ale z większym spinem w stylu C#..

Chciałbym (i często to robię) stworzyć klasę zawierającą wiele metod statycznych. Na przykład:

classdef Statistics

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

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

end

Ponieważ Metody są statyczne, nie musisz instancjonować klasy. Funkcje można wywołać w następujący sposób:

data = 1:10;

mean = Statistics.MyMean(data);
std = Statistics.MyStd(data);     
 11
Author: SmallJoeMan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-31 09:35:53

Definiuję wiele funkcji w jednym .m pliku z Octave, a następnie użyć polecenia z wewnątrz .plik m, w którym muszę skorzystać z funkcji z tego pliku:

source("mycode.m");

Nie wiem, czy jest to dostępne z 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
Author: J.D.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-13 01:14:45

Można również grupować funkcje w jednym pliku głównym razem z główną funkcją wyglądającą tak:

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

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

Wtedy wywołanie subfun1 wyglądałoby tak: str=main ('subfun1')

 3
Author: Thierry Dalon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-03 18:46:20

Od R2017b, nie jest to oficjalnie możliwe. W odpowiedniej dokumentacji stwierdza się, że:

Pliki programów mogą zawierać wiele funkcji. Jeśli plik zawiera tylko definicje funkcji, pierwsza funkcja jest funkcją główną i jest funkcją powiązaną z nazwą pliku przez MATLAB. Funkcje, które podążają za główną funkcją lub kodem skryptu, nazywane są funkcjami lokalnymi. Funkcje Lokalne są dostępne tylko w pliku.

Jednak, obejścia zaproponowane w innych odpowiedziach mogą osiągnąć coś podobnego.

 0
Author: Dev-iL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Próbowałem z SCFRench i z RU Hasha na oktawie.

i wreszcie działa: ale zrobiłem kilka modyfikacji

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

Można wywołać w innym pliku 'm':

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

aktualizacja:

Dodałem odpowiedź, ponieważani ani +72, ani +20nie działały w oktawie dla mnie. Ten, który napisałem działa idealnie (i testowałem go w zeszły piątek, kiedy później napisałem post).

 -1
Author: Gromph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-28 09:49:24