¿Es posible definir más de una función por archivo en MATLAB y acceder a ellas desde fuera de ese archivo?

217

Cuando estaba estudiando para obtener mi licenciatura en EE, MATLAB requería que cada función se definiera en su propio archivo, incluso si era de una sola línea.

Estoy estudiando para obtener un título de posgrado ahora, y tengo que escribir un proyecto en MATLAB. ¿Sigue siendo un requisito para las versiones más recientes de MATLAB?

Si es posible poner más de una función en un archivo, ¿hay alguna restricción para esto? Por ejemplo, ¿se puede acceder a todas las funciones del archivo desde fuera del archivo, o solo a la función que tiene el mismo nombre que el archivo?

Nota: Estoy usando la versión R2007b de MATLAB.

Nathan Fellman
fuente

Respuestas:

271

La primera función en un archivo m (es decir, la función principal ) se invoca cuando se llama a ese archivo m. No es necesario que la función principal tenga el mismo nombre que el archivo m, pero para mayor claridad debería serlo . Cuando la función y el nombre del archivo difieren, el nombre del archivo debe usarse para llamar a la función principal.

Todas las funciones posteriores en el archivo m, llamadas funciones locales (o "subfunciones" en la terminología anterior), solo pueden ser llamadas por la función principal y otras funciones locales en ese archivo m. Las funciones en otros archivos m no pueden llamarlos. A partir de R2016b, también puede agregar funciones locales a los scripts , aunque el comportamiento del alcance sigue siendo el mismo (es decir, solo se pueden invocar desde el script).

Además, también puede declarar funciones dentro de otras funciones. Estas se llaman funciones anidadas , y solo se pueden llamar desde la función en la que están anidadas. También pueden tener acceso a variables en funciones en las que están anidadas, lo que los hace bastante útiles, aunque un poco difíciles de trabajar.

Más comida para pensar ...

Hay algunas formas de evitar el comportamiento de alcance de la función normal descrito anteriormente, como pasar identificadores de función como argumentos de salida como se menciona en las respuestas de SCFrench y Jonas (que, a partir de R2013b, es facilitado por la localfunctionsfunción). Sin embargo, no sugeriría que sea un hábito recurrir a tales trucos, ya que probablemente haya opciones mucho mejores para organizar sus funciones y archivos.

Por ejemplo, digamos que usted tiene una función principal Aen un archivo-m A.m, junto con las funciones locales D, Ey F. Ahora digamos que usted tiene otras dos funciones relacionadas By Cen la M-archivos B.my C.m, respectivamente, que también quiere ser capaz de llamar D, Ey F. Aquí hay algunas opciones que tiene:

  • Poner D, Ey Fcada uno en sus propios archivos m separados, permitiendo que cualquier otra función los llame. La desventaja es que el alcance de estas funciones es grande y no se limita sólo A, By C, pero la ventaja es que esto es bastante simple.

  • Crear un defineMyFunctionsarchivo-m (como en Jonas ejemplo) con D, Ey Fcomo funciones locales y una función principal que simplemente devuelve las manijas a ellos. Esto le permite mantener D, Ey Fen el mismo archivo, pero no hace nada con respecto al alcance de estas funciones ya que cualquier función que pueda llamar defineMyFunctionspuede invocarlas. También debe preocuparse por pasar los identificadores de función como argumentos para asegurarse de tenerlos donde los necesita.

  • Copiar D, Ey Fen B.my C.mcomo funciones locales. Esto limita el alcance de su uso a solo A, By C, pero hace que la actualización y el mantenimiento de su código sean una pesadilla porque tiene tres copias del mismo código en diferentes lugares.

  • ¡Usa funciones privadas ! Si usted tiene A, By Cen el mismo directorio, puede crear un subdirectorio llamado privatey lugar D, Ey Fde allí, cada uno como un archivo-m separada. Esto limita su ámbito de aplicación por lo que sólo pueden ser llamados por funciones en el directorio inmediatamente superior (es decir A, By C) y los mantiene juntos en el mismo lugar (pero aún diferentes archivos-m):

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

Todo esto va un poco más allá del alcance de su pregunta, y probablemente sea más detallado de lo que necesita, pero pensé que sería bueno abordar la preocupación más general de organizar todos sus archivos m. ;)

gnovice
fuente
3
Los favoritos miradas opción de respuesta como esta ^, @idigas
Embert
1
@embert Supongo que se refería a la cuestión de favorecer una pregunta, que se puede votar independientemente de la preferencia.
OJFord
79

En general, la respuesta a su pregunta es no, no puede definir más de una función externamente visible por archivo. Sin embargo, puede devolver los identificadores de función a funciones locales, y una forma conveniente de hacerlo es convertirlos en campos de una estructura. Aquí hay un ejemplo:

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

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

function z=fun2
  z=1;
end

Y así es como podría usarse:

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

La única forma de tener múltiples funciones accesibles por separado en un solo archivo es definir MÉTODOS ESTÁTICOS utilizando programación orientada a objetos . Accedería a la función como myClass.static1(),myClass.static2() etc.

La funcionalidad OOP solo se admite oficialmente desde R2008a, por lo que, a menos que desee utilizar la sintaxis OOP antigua e indocumentada, la respuesta para usted es no, como explica @gnovice .

EDITAR

Una forma más de definir múltiples funciones dentro de un archivo que son accesibles desde el exterior es crear una función que devuelva múltiples identificadores de función . En otras palabras, llamaría a su función de definición como [fun1,fun2,fun3]=defineMyFunctions, después de lo cual podría usar, out1=fun1(inputs)etc.

Jonas
fuente
No usaría oop para este propósito, agrega una sobrecarga sustancial, especialmente para los métodos estáticos. ( stackoverflow.com/questions/1693429/… )
Daniel
1
@Daniel: La sobrecarga es notable solo si realiza una gran cantidad de llamadas a funciones y los cálculos en el método son casi instantáneos. Ambas condiciones a menudo apuntan a un mal diseño: sin vectorización y funciones sin sentido. Por lo tanto, no estaría demasiado preocupado.
Jonas
23

Realmente me gusta la respuesta de SCFrench: me gustaría señalar que se puede modificar fácilmente para importar las funciones directamente al espacio de trabajo utilizando la función de asignación. (Hacerlo de esta manera me recuerda mucho la forma de hacer las cosas "importar x de y" de 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

Y luego se usa así:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1
Ru Hasha
fuente
assignin('caller',...)Sería más correcto. Es posible que desee utilizar estas funciones desde otra función.
Cris Luengo
10

En la misma línea que la respuesta de SCFrench, pero con un giro más estilo C #.

Yo haría (y a menudo lo hago) una clase que contiene múltiples métodos estáticos. Por ejemplo:

classdef Statistics

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

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

end

Como los métodos son estáticos, no necesita instalar la clase. Llama a las funciones de la siguiente manera:

data = 1:10;

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

Defino múltiples funciones en un archivo .m con Octave y luego uso el comando desde dentro del archivo .m donde necesito hacer uso de las funciones de ese archivo:

source("mycode.m");

No estoy seguro si esto está disponible 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'.
JD
fuente
3

También puede agrupar funciones en un archivo principal junto con la función principal que se ve así:

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

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

Entonces llamar a subfun1 se vería así: str = main ('subfun1')

Thierry Dalon
fuente
0

A partir de R2017b, esto no es oficialmente posible. La documentación relevante establece que:

Los archivos de programa pueden contener múltiples funciones. Si el archivo contiene solo definiciones de funciones, la primera función es la función principal, y es la función que MATLAB asocia con el nombre del archivo. Las funciones que siguen a la función principal o al código del script se denominan funciones locales. Las funciones locales solo están disponibles dentro del archivo.

Sin embargo, las soluciones alternativas sugeridas en otras respuestas pueden lograr algo similar.

Diablo
fuente
¿Esto no es exactamente lo que Gnovice dijo al comienzo de su respuesta?
Adiel
@Adiel Quizás, pero han pasado varios años desde esa respuesta, y alguien podría preguntarse si algo cambió.
Dev-iL
Todavía no entendí si algo ha cambiado ...? :)
Adiel
No Aparte de tal vez alguna documentación que se agregó para abordar este tema específico.
Dev-iL
La razón por la que escribí esta respuesta es porque hace varios lanzamientos introdujeron funciones que puede agregar al final de los scripts , por lo que uno podría preguntarse si algo también cambió a este respecto (respuesta: no).
Dev-iL
-1

He intentado con SCFRench y con Ru Hasha en octava.

Y finalmente funciona: pero he hecho alguna modificación

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

Se puede llamar en otro archivo 'm':

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

actualizar:

Agregué una respuesta porque ni el +72 ni el +20 funcionaron en octava para mí. El que escribí funciona perfectamente (y lo probé el viernes pasado cuando más tarde escribí la publicación).

Gromph
fuente
2
Si puede explicar cómo esto es diferente de las dos respuestas existentes de las que está copiando, eliminaré mi voto negativo. Perdón por no comentar antes. Simplemente no veo cómo esto es diferente, excepto que combinó ambos métodos en una función y, por lo tanto, está haciendo algo redundante. Además, inserte los enlaces adecuados a las respuestas a las que hace referencia, "+72" y "+20" es bastante críptico, me tomó un tiempo darme cuenta de que se está refiriendo a los recuentos de votos, que cambiarán con el tiempo y harán sus referencias ininteligible
Cris Luengo