É possível definir mais de uma função por arquivo no MATLAB e acessá-las de fora desse arquivo?

216

Quando eu estava estudando para o curso de graduação em EE, o MATLAB exigia que cada função fosse definida em seu próprio arquivo, mesmo que fosse uma linha.

Estou estudando para uma pós-graduação agora e tenho que escrever um projeto no MATLAB. Isso ainda é um requisito para versões mais recentes do MATLAB?

Se for possível colocar mais de uma função em um arquivo, há alguma restrição para isso? Por exemplo, todas as funções no arquivo podem ser acessadas de fora do arquivo ou apenas a função que tem o mesmo nome que o arquivo?

Nota: Estou usando o MATLAB versão R2007b.

Nathan Fellman
fonte

Respostas:

270

A primeira função em um arquivo m (ou seja, a função principal ) é invocada quando esse arquivo m é chamado. Não é necessário que a função principal tenha o mesmo nome que o arquivo m, mas para maior clareza, deve . Quando a função e o nome do arquivo diferem, o nome do arquivo deve ser usado para chamar a função principal.

Todas as funções subseqüentes no arquivo m, chamadas funções locais (ou "subfunções" na terminologia antiga), só podem ser chamadas pela função principal e outras funções locais nesse arquivo m. Funções em outros arquivos m não podem chamá-los. A partir do R2016b, você pode adicionar funções locais aos scripts , embora o comportamento do escopo ainda seja o mesmo (ou seja, elas só podem ser chamadas de dentro do script).

Além disso, você também pode declarar funções dentro de outras funções. Essas são chamadas funções aninhadas e podem ser chamadas apenas de dentro da função em que estão aninhadas. Eles também podem ter acesso a variáveis ​​em funções nas quais estão aninhados, o que as torna bastante úteis, embora um pouco difíceis de trabalhar.

Mais comida para reflexão ...

Existem algumas maneiras de contornar o comportamento do escopo de função normal descrito acima, como passar identificadores de função como argumentos de saída, como mencionado nas respostas do SCFrench e Jonas (que, começando no R2013b, é facilitado pelolocalfunctions função). No entanto, eu não sugeriria criar o hábito de recorrer a esses truques, pois provavelmente existem opções muito melhores para organizar suas funções e arquivos.

Por exemplo, digamos que você tem uma função principal Aem um arquivo-m A.m, junto com funções locais D, Ee F. Agora, digamos que você tenha duas outras funções relacionadas Be Cnos arquivos m B.me C.m, respectivamente, que você também deseja chamar D,E e F. Aqui estão algumas opções que você tem:

  • Coloque D, Ee Fcada um em suas próprias m-arquivos separados, permitindo que qualquer outra função de chamá-los. A desvantagem é que o escopo dessas funções é grande e não está restrito a apenas A, Be C, mas a vantagem é que este é bastante simples.

  • Criar um defineMyFunctionsm-file (como no exemplo Jonas') com D, Ee Fcomo funções locais e uma função principal que simplesmente retorna funcionar identificadores para eles. Isso permite que você mantenha D, Ee Fno mesmo arquivo, mas não faz nada em relação ao escopo dessas funções, pois qualquer função que pode chamar defineMyFunctionspode invocá-las. Você também precisa se preocupar em passar as alças de função como argumentos para garantir que você as tenha onde precisar.

  • Copiar D, Ee Fem B.me C.mcomo funções locais. Isso limita o alcance de seu uso apenas A, BeC , mas marcas atualização e manutenção do seu código de um pesadelo, porque você tem três cópias do mesmo código em lugares diferentes.

  • Use funções privadas ! Se você tem A, Be Cno mesmo diretório, você pode criar um subdiretório chamado privatee lugar D, Ee Flá, cada um como uma m-arquivo separado. Isso limita o seu âmbito de modo que só pode ser chamado por funções no diretório imediatamente acima (ou seja A, B, e C) e mantém-los juntos no mesmo lugar (mas ainda diferentes m-files):

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

Tudo isso está um pouco fora do escopo da sua pergunta e provavelmente é mais detalhado do que você precisa, mas achei que seria bom abordar a preocupação mais geral de organizar todos os seus arquivos m. ;)

gnovice
fonte
3
A opção de resposta favorita fica assim ^, @idigas
embert 4/15
1
@embert Eu suponho que ele quis dizer ao longo da linha de favorecer uma pergunta, que pode ser votada independentemente, independentemente de favorecer.
OJFord 25/03
78

Geralmente, a resposta para sua pergunta é não, você não pode definir mais de uma função externamente visível por arquivo. Você pode retornar identificadores de funções para funções locais, e uma maneira conveniente de fazer isso é torná-los campos de uma estrutura. Aqui está um exemplo:

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

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

function z=fun2
  z=1;
end

E aqui está como ele pode ser usado:

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

A única maneira de ter várias funções acessíveis separadamente em um único arquivo é definir MÉTODOS ESTÁTICOS usando programação orientada a objetos . Você acessaria a função como myClass.static1(),myClass.static2() etc.

A funcionalidade OOP é oficialmente suportada apenas desde R2008a, portanto, a menos que você queira usar a sintaxe OOP antiga e não documentada, a resposta para você é não, conforme explicado por @gnovice .

EDITAR

Mais uma maneira de definir várias funções dentro de um arquivo acessível externamente é criar uma função que retorne vários identificadores de função . Em outras palavras, você chamaria sua função de definição como [fun1,fun2,fun3]=defineMyFunctions, após a qual você poderia usar out1=fun1(inputs)etc.

Jonas
fonte
Eu não usaria oop para esse fim, ele adiciona uma sobrecarga substancial, especialmente para métodos estáticos. ( stackoverflow.com/questions/1693429/… )
Daniel
1
@ Daniel: A sobrecarga é perceptível apenas se você fizer uma quantidade enorme de chamadas de função e os cálculos no método forem quase instantâneos. Ambas as condições geralmente apontam para um design ruim - sem vetorização e funções sem sentido. Assim, eu não ficaria muito preocupado.
Jonas
23

Gosto muito da resposta do SCFrench - gostaria de ressaltar que ele pode ser modificado facilmente para importar as funções diretamente para o espaço de trabalho usando a função assignin. (Fazer assim me lembra muito a maneira "import x from y" de Python de fazer as coisas)

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 então usado assim:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1
Ru Hasha
fonte
assignin('caller',...)seria mais correto. Você pode querer usar essas funções de dentro de outra função.
Cris Luengo
10

Na mesma linha da resposta do SCFrench, mas com uma rotação mais no estilo C # ..

Eu (e frequentemente faço) criaria uma classe contendo vários métodos estáticos. Por exemplo:

classdef Statistics

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

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

end

Como os métodos são estáticos, você não precisa instanciar a classe. Você chama as funções da seguinte maneira:

data = 1:10;

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

Eu defino várias funções em um arquivo .m com o Octave e, em seguida, uso o comando no arquivo .m, onde preciso fazer uso das funções desse arquivo:

source("mycode.m");

Não tenho certeza se isso está disponível no 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
fonte
3

Você também pode agrupar funções em um arquivo principal, juntamente com a função principal, com esta aparência:

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

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

Então chamar subfun1 ficaria assim: str = main ('subfun1')

Thierry Dalon
fonte
0

A partir do R2017b, isso não é oficialmente possível. A documentação relevante afirma que:

Os arquivos de programa podem conter várias funções. Se o arquivo contiver apenas definições de função, a primeira função será a principal e será a função que o MATLAB associa ao nome do arquivo. As funções que seguem a função principal ou o código de script são chamadas de funções locais. As funções locais estão disponíveis apenas dentro do arquivo.

No entanto, as soluções alternativas sugeridas em outras respostas podem obter algo semelhante.

Diabo
fonte
Não é exatamente isso que Gnovice afirmou no início de sua resposta?
Adiel 23/10
@ Adiel Talvez, mas vários anos se passaram desde essa resposta, e alguém pode se perguntar se algo mudou.
Dev-iL
Ainda não entendi se alguma coisa mudou ...? :)
Adiel
Não. Além de talvez alguma documentação que foi adicionada para abordar este tópico específico.
Dev-iL
A razão pela qual escrevi esta resposta é porque, em vários lançamentos atrás, eles introduziram funções que você pode adicionar ao final dos scripts - então, pode-se perguntar se algo também mudou nesse sentido (resposta: não).
Dev-iL
-1

Eu tentei com o SCFRench e com o Ru Hasha na oitava.

E finalmente funciona: mas eu fiz algumas modificações

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

Pode ser chamado em outro arquivo 'm':

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

atualizar:

Eu adicionei uma resposta porque nem o +72 nem o +20 funcionavam na oitava para mim. O que eu escrevi funciona perfeitamente (e eu testei na última sexta-feira, quando mais tarde escrevi o post).

Gromph
fonte
2
Se você puder explicar como isso é diferente das duas respostas existentes das quais você está copiando, removerei meu voto negativo. Desculpe por não comentar anteriormente. Só não vejo como isso é diferente, exceto que você combinou os dois métodos em uma função e, portanto, está fazendo algo redundante. Além disso, insira os links adequados para as respostas que você está referenciando, "+72" e "+20" é bastante enigmático, demorei um pouco para perceber que você está se referindo às contagens de votos, que mudarão com o tempo e farão suas referências ininteligível.
Cris Luengo 27/11