comando matlab reflection

comando - ¿Cómo recupero los nombres de los parámetros de función en matlab?



comando legend matlab (6)

inputname(argnum) http://www.mathworks.com/help/techdoc/ref/inputname.html .

Además de analizar el archivo de función, ¿hay alguna manera de obtener los nombres de los argumentos de entrada y salida para una función en matlab?

Por ejemplo, dado el siguiente archivo de función:

divide.m

function [value, remain] = divide(left, right) value = floor(left / right); remain = left / right - value; end

Desde fuera de la función, quiero obtener una matriz de argumentos de salida, aquí: [''value'', ''remain''] , y de manera similar para los argumentos de entrada: [''left'', ''right''] .

¿Hay alguna manera fácil de hacer esto en Matlab? Matlab por lo general parece apoyar la reflexión bastante bien.

EDITAR Antecedentes:

El objetivo de esto es presentar los parámetros de la función en una ventana para que el usuario ingrese. Estoy escribiendo un tipo de programa de procesamiento de señal, y las funciones para realizar operaciones en estas señales se almacenan en una subcarpeta. Ya tengo una lista y los nombres de cada función de la que el usuario puede seleccionar, pero algunas funciones requieren argumentos adicionales (por ejemplo, una función sin problemas puede tomar el tamaño de ventana como parámetro).

Por el momento, puedo agregar una nueva función a la subcarpeta que el programa encontrará, y el usuario puede seleccionarla para realizar una operación. Lo que me falta es que el usuario especifique los parámetros de entrada y salida, y aquí he topado con el obstáculo aquí porque no puedo encontrar los nombres de las funciones.


¿Has considerado usar contenedores de mapas?

Puedes escribir tus funciones en esta línea. . .

function [outMAP] = divide(inMAP) outMAP = containers.Map(); outMAP(''value'') = floor(inMAP(''left'') / inMAP(''right'')); outMAP(''remain'') = inMAP(''left'') / inMAP(''right'') - outMAP(''value''); end

... y llamarlos así ...

inMAP = containers.Map({''left'', ''right''}, {4, 5}); outMAP = divide(inMAP);

... y luego simplemente examinar los nombres de las variables usando la siguiente sintaxis ...

>> keys(inMAP) ans = ''left'' ''right''


Cuando no puede obtener información de un lenguaje de programación sobre su contenido (por ejemplo, "reflexión"), tiene que salir del idioma.

Otro cartel sugirió "expresiones regulares", que siempre fallan cuando se aplican al análisis de programas reales porque las expresiones regulares no pueden analizar lenguajes libres de contexto.

Para hacer esto de manera confiable, necesita un analizador de lenguaje M real, que le dará acceso al árbol de análisis sintáctico. Entonces esto es bastante fácil.

Nuestro DMS Software Reengineering Toolkit tiene un analizador de lenguaje M disponible para ello, y podría hacerlo.


Esto va a ser muy difícil (leer: imposible) para funciones generales (piense en cosas como varargin, etc.). Además, en general, depender de nombres de variables como una forma de documentación podría ser ... no lo que desea. Voy a sugerir un enfoque diferente.

Como usted controla el programa, ¿qué hay de especificar cada módulo no solo con el archivo m, sino también con una entrada de tabla con información adicional? Puede documentar los parámetros adicionales, la función en sí misma, anotar cuando las opciones son booleanas y presentarlas como casillas de verificación, etc.

Ahora, ¿dónde poner esto? Sugeriría que la función principal m-file devuelva la estructura, como una especie de paso de carga del módulo, con un identificador de función que apunta a la subfunción (o función anidada) que hace el trabajo real. Esto preserva la configuración de un solo archivo que estoy seguro desea conservar, y hace una configuración mucho más configurable para sus módulos.

function module = divide_load() module.fn = @my_divide; module.name = ''Divide''; module.description = ''Divide two signals''; module.param(1).name = ''left''; module.param(1).description = ''left signal''; module.param(1).required_shape = ''columnvector''; % Etc, etc. function [value, remain] = my_divide(left, right) value = floor(left / right); remain = left / right - value; end end


Si su problema se limita al caso simple en el que desea analizar la línea de declaración de función de una función principal en un archivo (es decir, no tratará con funciones secundarias , funciones anidadas o anónimas ), puede extraer la entrada y los nombres de los argumentos de salida tal como aparecen en el archivo usando algunas operaciones de cadena estándar y expresiones regulares . La línea de declaración de función tiene un formato estándar, pero debe contabilizar algunas variaciones debido a:

(Resulta que explicar un comentario en bloque fue la parte más difícil ...)

He creado una función get_arg_names que manejará todo lo anterior. Si le da una ruta al archivo de función, devolverá dos matrices de celdas que contienen sus cadenas de parámetros de entrada y salida (o matrices de celdas vacías si no hay ninguna). Tenga en cuenta que las funciones con listas de entrada o salida variables simplemente enumerarán ''varargin'' o ''varargout'' , respectivamente, para los nombres de las variables. Aquí está la función:

function [inputNames, outputNames] = get_arg_names(filePath) %# Open the file: fid = fopen(filePath); %# Skip leading comments and empty lines: defLine = ''''; while all(isspace(defLine)) defLine = strip_comments(fgets(fid)); end %# Collect all lines if the definition is on multiple lines: index = strfind(defLine, ''...''); while ~isempty(index) defLine = [defLine(1:index-1) strip_comments(fgets(fid))]; index = strfind(defLine, ''...''); end %# Close the file: fclose(fid); %# Create the regular expression to match: matchStr = ''/s*function/s+''; if any(defLine == ''='') matchStr = strcat(matchStr, ''/[?(?<outArgs>[/w, ]*)/]?/s*=/s*''); end matchStr = strcat(matchStr, ''/w+/s*/(?(?<inArgs>[/w, ]*)/)?''); %# Parse the definition line (case insensitive): argStruct = regexpi(defLine, matchStr, ''names''); %# Format the input argument names: if isfield(argStruct, ''inArgs'') && ~isempty(argStruct.inArgs) inputNames = strtrim(textscan(argStruct.inArgs, ''%s'', ... ''Delimiter'', '','')); else inputNames = {}; end %# Format the output argument names: if isfield(argStruct, ''outArgs'') && ~isempty(argStruct.outArgs) outputNames = strtrim(textscan(argStruct.outArgs, ''%s'', ... ''Delimiter'', '','')); else outputNames = {}; end %# Nested functions: function str = strip_comments(str) if strcmp(strtrim(str), ''%{'') strip_comment_block; str = strip_comments(fgets(fid)); else str = strtok(['' '' str], ''%''); end end function strip_comment_block str = strtrim(fgets(fid)); while ~strcmp(str, ''%}'') if strcmp(str, ''%{'') strip_comment_block; end str = strtrim(fgets(fid)); end end end


MATLAB ofrece una forma de obtener información sobre los metadatos de la clase (utilizando el meta paquete), sin embargo, esto solo está disponible para las clases OOP que no son funciones regulares.

Un truco es escribir una definición de clase sobre la marcha, que contiene la fuente de la función que le gustaría procesar, y dejar que MATLAB se ocupe del análisis sintáctico del código fuente (que puede ser complicado como se imaginaría: línea de definición de función) abarca múltiples líneas, comentarios antes de la definición real, etc.)

Entonces, el archivo temporal creado en su caso se vería así:

classdef SomeTempClassName methods function [value, remain] = divide(left, right) %# ... end end end

que luego se puede pasar a meta.class.fromName para analizar metadatos ...

Aquí hay una implementación rápida y sucia de este truco:

function [inputNames,outputNames] = getArgNames(functionFile) %# get some random file name fname = tempname; [~,fname] = fileparts(fname); %# read input function content as string str = fileread(which(functionFile)); %# build a class containing that function source, and write it to file fid = fopen([fname ''.m''], ''w''); fprintf(fid, ''classdef %s; methods;/n %s/n end; end'', fname, str); fclose(fid); %# terminating function definition with an end statement is not %# always required, but now becomes required with classdef missingEndErrMsg = ''An END might be missing, possibly matching CLASSDEF.''; c = checkcode([fname ''.m'']); %# run mlint code analyzer on file if ismember(missingEndErrMsg,{c.message}) % append "end" keyword to class file str = fileread([fname ''.m'']); fid = fopen([fname ''.m''], ''w''); fprintf(fid, ''%s /n end'', str); fclose(fid); end %# refresh path to force MATLAB to detect new class rehash %# introspection (deal with cases of nested/sub-function) m = meta.class.fromName(fname); idx = find(ismember({m.MethodList.Name},functionFile)); inputNames = m.MethodList(idx).InputNames; outputNames = m.MethodList(idx).OutputNames; %# delete temp file when done delete([fname ''.m'']) end

y simplemente ejecuta como:

>> [in,out] = getArgNames(''divide'') in = ''left'' ''right'' out = ''value'' ''remain''