Чи можна визначити більше однієї функції на файл у MATLAB та отримати доступ до них поза цим файлом?


217

Коли я навчався на бакалавраті з ЕЕ, MATLAB вимагав, щоб кожна функція була визначена у власному файлі, навіть якщо це була однолінійна.

Зараз я навчаюся на диплом, і мені потрібно написати проект у MATLAB. Це все-таки вимога до новіших версій MATLAB?

Якщо в файл можна поставити кілька функцій, чи існують обмеження на це? Наприклад, чи можна отримати доступ до всіх функцій у файлі за межами файлу, або лише функція, яка має те саме ім'я, що і файл?

Примітка: я використовую реліз MATLAB R2007b.

Відповіді:


271

Перша функція m-файлу (тобто основна функція ) викликається при виклику цього m-файлу. Не потрібно, щоб основна функція мала те саме ім'я, що і m-файл, але для наочності це повинно бути . Якщо функція та ім'я файлу різняться, ім'я файлу потрібно використовувати для виклику основної функції.

Усі наступні функції в m-файлі, що називаються локальними функціями (або "підфункціями" у старій термінології), можна викликати лише основною функцією та іншими локальними функціями у цьому m-файлі. Функції в інших m-файлах не можуть їх викликати. Починаючи з R2016b, ви можете додавати локальні функції до сценаріїв , хоча поведінка в масштабі все ще однакова (тобто їх можна викликати лише з сценарію).

Крім того, ви також можете оголошувати функції в межах інших функцій. Вони називаються вкладеними функціями , і їх можна викликати лише з тієї функції, яку вони вкладаються. Вони також можуть мати доступ до змінних у функціях, в яких вони вкладені, що робить їх досить корисними, хоча і трохи складними для роботи.

Більше їжі для роздумів ...

Існують деякі способи навколо поведінки щодо нормального визначення функцій, викладених вище, наприклад, передача ручок функції як вихідних аргументів, як згадується у відповідях SCFrench і Jonas (що, починаючи з R2013b, полегшується localfunctionsфункцією). Однак я б не радив робити звичку вдаватися до подібних хитрощів, оскільки, ймовірно, набагато кращі варіанти організації ваших функцій та файлів.

Наприклад, припустимо, що у вас є основна функція Aв м-файлі A.m, поряд з локальними функціями D, Eі F. Тепер припустимо, що у вас є два інших пов'язаних з ними функцій Bі Cв м-файлів B.mі C.m, відповідно, що ви хочете бути в змозі назвати D, Eі F. Ось кілька варіантів:

  • Покладіть D, Eі Fкожен у свої окремі m-файли, що дозволяє будь-якій іншій функції викликати їх. Недоліком є те, що сфера застосування цих функцій великий і не обмежується тільки A, Bі C, але вгору, що це досить просто.

  • Створіть defineMyFunctionsm-файл (як у прикладі Йонаса) за допомогою D, Eі, Fяк локальні функції та головну функцію, яка просто повертає функції функцій для них. Це дозволяє зберегти D, Eі Fв тому ж файлі, але це нічого не робити в відношенні обсягу цих функцій , так як будь-яка функція , яка може викликати defineMyFunctionsїх виклику. Потім вам доведеться турбуватися про передачу функції функції як аргументи, щоб переконатися, що у вас є їх там, де вони вам потрібні.

  • Копіювання D, Eі Fв B.mі в C.mякості локальних функцій. Це обмежує сферу їх використання просто A, Bі C, але робить оновлення та підтримку коду кошмаром, оскільки у вас є три копії одного і того ж коду в різних місцях.

  • Використовуйте приватні функції ! Якщо у вас є A, Bі Cв тому ж каталозі, ви можете створити підкаталог privateі місце D, Eі Fтам, кожен як окремий м-файл. Це обмежує сферу їх застосування , так що вони можуть бути викликані тільки функціями в каталозі безпосередньо вище (тобто A, Bі C) і тримає їх разом в одному місці (але все ж різні м-файли):

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

Все це дещо виходить за рамки вашого питання, і, мабуть, більш детально, ніж вам потрібно, але я подумав, що було б корисно торкнутися більш загальної турботи щодо організації всіх ваших m-файлів. ;)


3
Улюблений варіант відповіді виглядає так ^: @idigas
embert

1
@embert Я припускаю, що він мав на увазі фаворитизувати питання, яке може бути додано до голосування незалежно від фавориту.
OJFord

79

Як правило, відповідь на ваше запитання - ні. Ви не можете визначити більше однієї зовнішньої функції на файл. Однак ви можете повернути ручки функцій до локальних функцій, і зручний спосіб зробити це - зробити їх полями структури. Ось приклад:

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

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

function z=fun2
  z=1;
end

А ось як це можна було використовувати:

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

36

Єдиний спосіб мати кілька, окремо доступних функцій в одному файлі - це визначити СТАТИЧНІ МЕТОДИ за допомогою об'єктно-орієнтованого програмування . Ви отримаєте доступ до функції як myClass.static1(),myClass.static2() і т.д.

Функція OOP підтримується лише офіційно з R2008a, тому, якщо ви не хочете використовувати старий, недокументований синтаксис OOP, відповідь для вас - ні, як пояснив @gnovice .

EDIT

Ще одним способом визначення декількох функцій у файлі, доступних зовні, є створення функції, яка повертає кілька функцій ручок . Іншими словами, ви б назвали свою визначальну функцію такою [fun1,fun2,fun3]=defineMyFunctions, після чого ви можете використовувати out1=fun1(inputs)і т.д.


Я б не використовував oop для цієї мети, це додає значних витрат, особливо для статичних методів. ( stackoverflow.com/questions/1693429/… )
Даніель

1
@Daniel: Накладні витрати помітні лише в тому випадку, якщо ви виконуєте величезну кількість викликів функцій, і обчислення в методі є квазимоментальними. Обидві умови часто вказують на поганий дизайн - не векторизацію та безглузді функції. Таким чином, я б не надто хвилювався.
Йонас

23

Мені дуже подобається відповідь SCFrench - я хотів би зазначити, що її можна легко змінити, щоб імпортувати функції безпосередньо в робочу область за допомогою функції присвоєння. (Це робиться так, що мені дуже нагадує спосіб "імпортувати x з y" 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

А потім використовується таким чином:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1

assignin('caller',...)було б правильніше. Ви можете використовувати ці функції з іншої функції.
Кріс Луенго

10

Відповідно до відповіді SCFrench, але з більш стильним стилем C #.

Я б (і часто це роблю) склав клас, що містить декілька статичних методів. Наприклад:

classdef Statistics

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

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

end

Оскільки методи є статичними, вам не потрібно встановлювати клас. Ви викликаєте функції таким чином:

data = 1:10;

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

4

Я визначаю кілька функцій у одному .m-файлі за допомогою Octave, а потім використовую команду з файлу .m, де мені потрібно використовувати функції з цього файлу:

source("mycode.m");

Не впевнений, чи це доступно в 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

Ви також можете групувати функції в одному головному файлі разом з основною функцією, виглядаючи так:

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

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

Тоді виклик subfun1 виглядатиме так: str = main ('subfun1')


0

Станом на R2017b це офіційно неможливо. У відповідній документації зазначено, що:

Програмні файли можуть містити кілька функцій. Якщо файл містить лише визначення функцій, перша функція є основною функцією, і це функція, яку MATLAB асоціює з ім'ям файлу. Функції, які слідують за основною функцією або кодом сценарію, називаються локальними функціями. Локальні функції доступні лише у файлі.

Однак способи вирішення, запропоновані в інших відповідях, можуть досягти чогось подібного.


Це не зовсім те, про що Гновіце заявив на початку своєї відповіді?
Адіель

@Adiel Можливо, але минуло кілька років з моменту цієї відповіді, і хтось може поцікавитися, чи щось змінилося.
Dev-iL

Я все одно не отримав, якщо щось змінилося ...? :)
Адіель

Ні. Окрім, можливо, деякої документації, яка була додана для вирішення цієї конкретної теми.
Dev-iL

Причина, чому я написав цю відповідь, полягає в тому, що кілька випусків тому вони запровадили функції, які можна додати до кінця сценаріїв, тож можна поцікавитись, чи змінилось і в цьому плані (відповідь: ні).
Dev-iL

-1

Я спробував з SCFRench і з Ru Hasha на октаві.

І, нарешті, це працює: але я зробив певну модифікацію

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

Можна викликати інший 'm' файл:

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

оновлення:

Я додав відповідь, тому що ні +72, ні +20 не працювали для мене в октаві. Той, кого я написав, працює чудово (і я перевірив його минулої п’ятниці, коли пізніше написав пост).


2
Якщо ви зможете пояснити, чим це відрізняється від двох існуючих відповідей, з яких ви копіюєте, я видалю свою анкету. Вибачте, що раніше не коментували. Я просто не бачу, як це по-різному, за винятком того, що ви поєднали обидва методи в одну функцію і, отже, робите щось зайве. Крім того, будь ласка, вставте належні посилання на відповіді, на які ви посилаєтесь, "+72" та "+20" є доволі виразним, мені знадобилося певний час, щоб зрозуміти, що ви маєте на увазі підрахунок голосів, який з часом зміниться та зробить ваші посилання незрозумілий.
Кріс Луенго
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.