打印当前代码行和特定变量'名称,类型和尺寸

时间:2017-07-27 09:18:42

标签: matlab debugging octave

要调试我的Octave / MATLAB代码,我希望能够执行以下操作:

A = magic(3);
b = 42;
describe(@A, @b);

并获得如下输出:

filename.m line 3: "A" is a 3x3 matrix
filename.m line 3: "b" is a scalar of value: 42

对于多个变量,我该如何打印:

  • 调用功能的文件和行
  • 名称
  • 输入
  • 尺寸

3 个答案:

答案 0 :(得分:5)

概述

在这个答案中,我列出了3个不同版本的函数describe

  1. 获取任意数量的变量并创建输出字符串并使用fpritnf
  2. 显示它
  3. 获取任意数量的变量并创建输出单元格数组并使用disp
  4. 显示它
  5. 采用任意数量的变量名称并创建一个输出字符串,如1所示。这样做的好处是能够处理像describe('myvar{1}')这样的索引。
  6. 主要功能说明和版本1.

    您可以使用各种标准功能获取所需信息:

    • varargin接受可变数量的输入变量
    • dbstack获取文件名/当前行
    • inputname获取传入describe
    • 时输入的名称
    • fprintf以新行字符显示
    • varargout可选择返回或显示结果

    所以像这样创建你的describe函数:

    function varargout = describe(varargin)
        % varargin used to accomodate variable number of inputs
        % By default, at least get functions stack (even if no variables are passed in)
        st = dbstack;
        % Convert cell output to string (excluding describe.m itself)
        outstring = '';
        % Loop backwards for more logical order (most recent last)
        for ii = size(st, 1):-1:2
            % new line character at end only works with fprintf, not disp
            outstring = [outstring, st(ii).file, ' > ', st(ii).name, ...
                         ', line ', num2str(st(ii).line), '\n'];
        end
        % Loop over variables and get info
        for n = 1:nargin
            % Use inputname to get name of input variables
            outstring = [outstring, '"', inputname(n), '" is a ', ...
                         class(varargin{n}), ' of size ', mat2str(size(varargin{n})), '\n'];
        end
        % If output variable is requested then assign to output variable
        % If not, just display output string to command window 
        if nargout 
            varargout{1} = outstring;
        else
            fprintf(outstring)
        end
    end 
    

    这里唯一需要的调整就是格式化,所有您要求的功能都在这里,希望有足够的灵活性来满足您的需求。

    示例输出

    % In myMainFunction.m, in the subfunction mySubFunction
    % Could store output using 'd = describe(A,B);' and use 'fprintf' later 
    describe(A, B);
    % In the command window
    myMainFunction.m > myMainFunction, line 3
    myMainFunction.m > mySubFunction, line 39
    "A" is a double of size [1 3]
    "B" is a double of size [1 5 9 7]
    

    在Matlab R2015b中测试过,上面列出的所有函数都是在R2006a之前根据文档存在的,因此我假设它们可能具有Octave等价物。

    第2版。

    单元格而不是带行分隔符的字符串。

    这有一个不太漂亮的输出,但也可能是一个不太笨重的方法,将字符串分配给单元格数组,而不是依赖fprintf新行。可以使用以下(简称未注释)版本轻松完成。

    function varargout = describe(varargin)
        st = dbstack; outcell = {};
        for ii = size(st, 1):-1:2
            outcell{end+1} = [st(ii).file, ' > ', st(ii).name, ', line ', num2str(st(ii).line)];
        end
        for n = 1:nargin
            outcell{end+1} = ['"', inputname(n), '" is a ',  class(varargin{n}), ' of size [', size(varargin{n}), ']'];
        end
        outcell = outcell.'; % Transpose to make it a column cell array
        disp(outcell)
    end 
    

    第3版。

    将变量名称作为字符串传递,因此会显示'myvar(1)'之类的内容。

    这使用evalin来评估caller工作空间(调用describe的位置)中的变量。注意:当您在此describe函数中重新创建变量以获取其属性时,这可能会占用大量内存。

    function varargout = describe(varargin)
        % varargin used to accomodate variable number of input names
        st = dbstack;
        outstring = '';
        for ii = size(st, 1):-1:2
            outstring = [outstring, st(ii).file, ' > ', st(ii).name, ', line ', num2str(st(ii).line), '\n'];
        end
        % Loop over variables and get info
        for n = 1:nargin
            % Variables are passed by name, so check if they exist
            try v = evalin('caller', varargin{n});
                outstring = [outstring, '"', varargin{n}, '" is a ', class(v), ' of size ', mat2str(size(v)), '\n'];   
            catch
                outstring = [outstring, 'Variable "', varargin{n}, '" not found!\n'];
            end
        end
        fprintf(outstring)
    end 
    

    使用示例:

    % This can be used with indexed variables too. MUST PASS STRINGS!
    describe('C{1}', 'B(1:2, :)')
    % In the command window
    myMainFunction.m > myMainFunction, line 3
    myMainFunction.m > mySubFunction, line 39
    "C{1}" is a double of size [1 3]
    "B(1:2, :)" is a double of size [2 5]
    
    % Because you're passing strings, you can use command syntax if you want
    % Gives same result but don't have to pass strings 
    % as that's how inputs are interpreted anyway for command syntax.
    describe C{1} B(1:2, :)
    

答案 1 :(得分:1)

我自己使用类似的东西。这是我的:

function describe(A)
  fprintf('       Class : %s\n',class(A));
  fprintf('  Num. Elems : %s\n',num2str(numel(A)));  
  fprintf('        Size : %s\n',num2str(size(A)));
  fprintf('   Total Min : %s\n',num2str(min (A(:))));
  fprintf('   Total Max : %s\n',num2str(max (A(:))));  
  fprintf('   Total Sum : %s\n',num2str(sum (A(:))));
  fprintf('  Total Mean : %s\n',num2str(mean(A(:))));
  fprintf('Total St.Dev : %s\n',num2str(std (A(:), 1)));
  fprintf(' Unique vals : %s\n',num2str(length(unique(A))));  
end

编辑:我知道这并不是您要求的字面答案,但我一直都在使用它,并认为分享可能会有用。 :)

<子> PS。话虽如此,我从未想过我可能想要以非交互方式使用这样的函数:如果我需要以这种方式检查变量,我只需要设置一个断点(或keyboard指令)在代码中,然后检查终端中与其最相关的位置的内容,因此我手动报告文件名和亚麻布!您需要执行这样的非交互式调试的用例是什么?如果它用于验尸&#34;测试&#34;无论如何,你真的应该写出正确的测试和健全性检查!

此外,这仅适用于单个变量,但我发现这更好;如果你想要更多,它是一个非常简单的单行循环。

答案 2 :(得分:0)

您可以使用size来获取变量的大小,类型使用class,名称使用inputname。 例如:

function describe(a)
  s = size(a); % Return the size of a
  t = class(a); % Return the type of a
  name = inputname(1); % Return the name of a

  printf(['filename.m line 3: ''''' name ''''' size:' s(1) 'x' s(2) ' and type: ' t]);
end

我不知道如何使用文件名和行,如果你想用另一种方式显示它,你可以使用if条件从矩阵中的向量中分离标量。