【问题标题】:Ideas / best practices for controlling verbosity in matlab functions在 matlab 函数中控制冗长的想法/最佳实践
【发布时间】:2013-08-01 04:55:15
【问题描述】:

假设我有 some_fun 可以做一些复杂的工作。

function foo = some_complicated_fun(x,y,z,verbosity)

我已经在这段代码中写了很多调试打印,但是如果它正常工作,普通用户可能对查看所有这些内容不感兴趣。 无论如何都会打印错误语句(没有足够的参数等)。

我目前编写函数的方法是:

function foo = some_complicated_fun(x,y,z,verbosity)

(x,y,z,verbosity) = parse_args(x,y,z,verbosity); % parse args, check nargin, etc

for i=1:5, 

    % whatever    
    % do some work with x,y,z
    % blah blah

    if verbosity 
        fprintf('Now on iteration %i\n',i); % basic print
    end

    % or, with mutiple levels:
    if verbosity == 1;
        fprintf('Now on iteration %i\n',i); % basic print
    end
    if verbosity == 2;
        fprintf('x = %f,y = %f,z=%f %i\n',x,y,z); % more information
    end

    % do more work

end

我不喜欢使用 if 语句来做这件事,因为它会使代码变得混乱,但我想不出任何其他方式。 一个班轮更好或更差:

if verbosity; fprintf('Iteration %i\n',i); end

更好是因为它更小,更糟糕是因为单行代码比 3 行代码的可读性差。

我想要的是一些简单、更优雅的方式来控制冗长。

存在吗?

【问题讨论】:

    标签: matlab printf verbosity clarity


    【解决方案1】:

    这就是我最终要做的。

    我写了一个函数(我叫它vprintf,但还有更好的名字。)

    我不确定我是否想做全局变量,但这是一个想法。

    function vprintf(v,l,varargin)
    % VPRINTF(verbosity, verbosity_level_of_statement,sprintf_style_arguments
    % 
    % 
    % example: 
    % 
    % verbosity = 1;
    % vprintf(verbosity,1,'This will print if verbosity is at least 1\n Verbosity = %i\n',verbosity);
    
    if nargin<3
        error('not enough arguments');
    end
    if v>=l % if verbosity level is >= level of this statment
    %     keyboard;
        fprintf(varargin{:});
    end
    

    【讨论】:

      【解决方案2】:

      我创建了一种方法来控制日志输出的详细程度。它还没有完成,但是自从出现这个问题后,我将其上传到:

      This link at Matlab File Exchange.

      它通过将全局输出日志设置为所需的级别来工作,并将按以下格式显示消息:

      OUTPUT_LEVEL:  function_which_called_message       Your_Message.
      

      但是,它只会输出高于您设置的输出级别的消息。默认情况下只显示 INFO 消息或更高级别的消息,因此不会显示 DEBUG 和 VERBOSE 消息。如果您想查看调试消息,请设置:

      Output.level(Output.DISP_DEBUG)
      

      输出方法有:

      Output.VERBOSE
      Output.DEBUG
      Output.INFO
      Output.WARNING
      Output.ERROR 
      

      您可以通过Output.'DESIRED_LEVEL'('message',input_1,input2) 选择要在函数中显示的消息,如sprintffprintf matlab 格式。即Output.INFO('The variable value is %d',variable)。对于 WARNING 和 ERROR 消息,您还可以将标识符指定为 'PACKAGE:METHOD:ERROR_ID',通过这样做,输出将在 matlab 的 warningerror 函数上。即Output.WARNING('MY_PACKAGE:MY_METHOD:MY_ID','Something wrong happened here!')

      可用的输出级别是:

      Output.level(Output.DISP_VERBOSE) % Show all messages
      Output.level(Output.DISP_DEBUG) % Show debug info warning errors
      Output.level(Output.DISP_INFO) % Show info warning errors
      Output.level(Output.DISP_WARNING) % Show warning errors
      Output.level(Output.DISP_MUTE) % Show only errors.
      

      您还可以使用指定输出到日志文件

      Output.place('file_path')
      

      并替换日志文件(你也可以用它来重置当前日志):

      Output.place('file_path',true)
      

      或将其重置为屏幕

      Output.place(1)
      

      这是使用输出级别 DISP_VERBOSE 的输出示例:

      >> nilmContainer = NilmFileContainer.newRun('inputFolder','sim_real/','runName','RealHouse','samplesPerFile',60*60*60);
      VERBOSE: getFilesOnFolder               Found 2 files on folder 'data/sim_real/'. They are the following:
      VERBOSE: getFilesOnFolder                   [1]:data/sim_real/240AM000.csv
      VERBOSE: getFilesOnFolder                   [2]:data/sim_real/240AM001.csv
      DEBUG:   NilmFileContainer.setRunName   Updating run name to RealHouse_Run5.
      INFO:    newRun                         Reading file data/sim_real/240AM000.csv.
      VERBOSE: csv_data                       Reading samples (Ignored:0,Read:216000,Remaining:2422014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_1-19:12:46-30_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:216000,Read:216000,Remaining:2206014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_2-20:12:45-30_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:432000,Read:216000,Remaining:1990014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_3-21:12:45-30_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:648000,Read:216000,Remaining:1774014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_4-22:12:45-30_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:864000,Read:216000,Remaining:1558014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_5-23:12:45-30_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:1080000,Read:216000,Remaining:1342014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_6-00:12:44-31_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:1296000,Read:216000,Remaining:1126014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_7-01:12:43-31_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:1512000,Read:216000,Remaining:910014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_8-02:12:43-31_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:1728000,Read:216000,Remaining:694014) at file: sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_9-03:12:43-31_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:1944000,Read:216000,Remaining:478014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_10-04:12:42-31_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:2160000,Read:216000,Remaining:262014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_11-05:12:41-31_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:2376000,Read:216000,Remaining:46014) at file: data/sim_real/240AM000.csv.
      DEBUG:   addFiles                       Writing file 'data/NILM_DATA/RealHouse_Run5/RealHouse_Run5-File_12-06:12:41-31_10_2012.mat'
      VERBOSE: csv_data                       Reading samples (Ignored:2592000,Read:46014,Remaining:0) at file: data/sim_real/240AM000.csv.
      VERBOSE: csv_data                       Reading samples (Ignored:0,Read:169986,Remaining:2799058) at file: data/sim_real/240AM001.csv.
      INFO:    readFile                       Found discontinuity while changing from file 'data/sim_real/240AM000.csv' to 'data/sim_real/240AM001.csv'.
      

      正如我所说,它不是最终版本,但你可以帮助我改进它! x)

      【讨论】:

        【解决方案3】:

        定义一个函数来替换fprintf,其中包含if 语句和实际打印。并将verbosity 声明为global 变量,以避免每次都将其作为参数传递。

        【讨论】:

          【解决方案4】:

          作为对 Frederick 和 Luis Mendo 答案的改进,您可以在函数末尾将 vprintf 函数定义为 nested function。它将可以访问参数verbosity,并且您不需要全局变量。您的代码如下所示:

          function foo = some_complicated_fun(x,y,z,verbosity)
          
          [x,y,z,verbosity] = parse_args(x,y,z,verbosity); % parse args, check nargin, etc
          
          for i=1:5, 
          
              % whatever    
              % do some work with x,y,z
              % blah blah
          
              vprintf(1,'Now on iteration %i\n',i); % basic print
          
              % or, with mutiple levels:
              vprintf(1,'Now on iteration %i\n',i); % basic print
              vprintf(2,'x = %f,y = %f,z=%f %i\n',x,y,z); % more information
          
              % do more work
          end
          
              % time to define vprintf
              function vprintf(l,varargin)
              % VPRINTF(verbosity, verbosity_level_of_statement,sprintf_style_arguments
              % 
              % 
              % example: 
              % 
              % verbosity = 1;
              % vprintf(1,'This will print if verbosity is at least 1\n Verbosity = %i\n',verbosity);
          
              if nargin<2
                  error('not enough arguments');
              end
              if verbosity>=l % if verbosity level is >= level of this statment
              %     keyboard;
                  fprintf(varargin{:});
              end
          end
          

          编辑 为了克服 cmets 中提到的 Gunther Struyf 的可维护性问题,您可以将 verbosity 值保留在 vprintf 的持久变量中,并在第一次调用时设置它。

          function vprintf(vl,varargin)
          % VPRINTF(verbosity);
          % VPRINTF(verbosity_level_of_statement,sprintf_style_arguments);
          
          persistent verbosity
          if nargin==1
              verbosity = vl;
          elseif isempty(verbosity)
              error('verbosity level not set');
          end
          
          if verbosity>=vl % if verbosity level is >= level of this statment
          %     keyboard;
              fprintf(varargin{:});
          end
          

          然后在foo 函数的开头设置它并在后面的语句中使用它。通过vprintf([]);清除出口中的值可能是一个好习惯@

          function foo = some_complicated_fun(x,y,z,verbosity)
          
          [x,y,z,verbosity] = parse_args(x,y,z,verbosity); % parse args, check nargin, etc
          
          vprintf(verbosity);
          for i=1:5, 
          
              % whatever    
              % do some work with x,y,z
              % blah blah
          
              vprintf(1,'Now on iteration %i\n',i); % basic print
          
              % or, with mutiple levels:
              vprintf(1,'Now on iteration %i\n',i); % basic print
              vprintf(2,'x = %f,y = %f,z=%f %i\n',x,y,z); % more information
          
              % do more work
          end
          vprintf([]);
          

          【讨论】:

          • 但是您必须将其复制到您使用/使用该功能的每个函数中,这会很痛苦,特别是如果您决定更改该嵌套函数中的某些内容
          • @GuntherStruyf 是的。取决于此构造在整个代码库中的流行程度。我添加了另一个使用持久变量而不是全局变量的解决方案。
          【解决方案5】:

          如果我想这样做,我会创建一个类似于 this 的 Logger 类,其功能包括 logDebuglogInfologWarninglogError。 (实际上我已经为 lua here 做了这个)。

          您必须在创建时设置日志级别,并且可以在 Logger 对象的范围内访问完整的功能和功能(因此没有全局范围污染,并且可以在多个 m 文件中轻松实现)。

          所以这个类的最终使用应该是这样的:

          %% my fancy script
          % init
          logger = Logger(Logger.LOGDEBUG)
          logger.logDebug('script initialized');
          
          % plot some stuff
          logger.logDebug('commencing plot');
          plot(rand(4));
          logger.logInfo('fancy script ended');
          

          【讨论】:

            猜你喜欢
            • 2017-09-13
            • 1970-01-01
            • 1970-01-01
            • 2010-09-21
            • 2015-09-04
            • 1970-01-01
            • 2011-06-29
            • 2018-09-24
            • 1970-01-01
            相关资源
            最近更新 更多