How to wrap an already existing function with a new function of the same name

后端 未结 3 957
忘掉有多难
忘掉有多难 2020-12-06 13:37

Is it possible to create a wrapper around a function that has the exact same name as the original function?

This would be very useful in circumstances where the user

相关标签:
3条回答
  • 2020-12-06 13:59

    I prefer jmetz's approach using builtin() when it can be applied, because it is clean and to the point. Unfortunately, many many functions are not found by builtin().

    I found that I was able to wrap a function using a combination of the which -all and cd commands. I suspect that this approach can be adapted to a wide variety of applications.

    In my example case, I wanted to (temporarily) wrap the interp1 function so that I could check for NaN output values. (The interp1 function will, by default, return a NaN under some conditions, such as if a query point is larger than the largest sample point.) Here's what I came up with:

    function Vq = interp1(varargin)
    
       persistent interp1_builtin;
    
       if (isempty(interp1_builtin)) % first call: handle not set
          toolbox = 'polyfun';
    
          % get a list of all known instances of the function, and then 
          % select the first such instance that contains the toolbox name
          % in its path
    
          which_list = which('interp1','-all');
          for ii = 1:length(which_list)
             if (strfind(which_list{ii}, [filesep, toolbox, filesep]))
                base_path = fileparts(which_list{ii}); % path to the original function
                current_path = pwd;
                cd(base_path); % go to the original function's directory
                interp1_builtin = @interp1; % create a function handle to the original function
                cd(current_path); % go back to the working directory
                break
             end
          end
       end
    
       Vq = interp1_builtin(varargin{:});  % call the original function
    
       % test if the output was NaN, and print a message
       if (any(isnan(Vq)))
          dbstack;
          disp('ERROR: interp1 returned a NaN');
          keyboard
       end
    
    end
    

    See also: How to use MATLAB toolbox function which has the same name of a user defined function

    0 讨论(0)
  • 2020-12-06 14:13

    Actually alternatively to slayton's answer you don't need to use openvar. If you define a function with the same name as a matlab function, it will shadow that function (i.e. be called instead).

    To then avoid recursively calling your own function, you can call the original function from within the wrapper by using builtin.

    e.g.

    outputs = builtin(funcname, inputs..);
    

    Simple example, named rand.m and in the matlab path:

    function out = main(varargin)
    disp('Test wrapping rand... calling rand now...');
    out = builtin('rand', varargin{:});
    

    Note that this only works for functions that are found by builtin. For those that are not, slayton's approach is likely necessary.

    0 讨论(0)
  • 2020-12-06 14:15

    Yes this is possible but it requires a bit of hacking. It requires that you copy around some function handles.

    Using the example provided in the question I will show how to wrap the function openvar in a user defined function that checks the size of the input variable and then allows the user to cancel any open operation for variables that are too large.

    Additionally, this should work when the user double clicks a variable in the Workspace pane of the Matlab IDE.

    We need to do three things.

    1. Get a handle to the original openvar function
    2. Define the wrapper function that calls openvar
    3. Redirect the original openvar name to our new function.

    Example Function

    function openVarWrapper(x, vector)
    
        maxVarSize = 10000;
        %declare the global variable
        persistent openVarHandle; 
    
        %if the variable is empty then make the link to the original openvar
        if isempty(openVarHandle)
            openVarHandle = @openvar;
        end
    
        %no variable name passed, call was to setup connection
        if narargin==0
            return;
        end
    
    
        %get a copy of the original variable to check its size
        tmpVar = evalin('base', x);        
    
        %if the variable is big and the user doesn't click yes then return
        if prod( size( tmpVar)) > maxVarSize
            resp = questdlg(sprintf('Variable %s is very large, open anyway?', x));
            if ~strcmp(resp, 'Yes')
                return;
            end
        end
    
        if ischar(x) && ~isempty(openVarHandle);
            openVarHandle(x);
         end
     end
    

    Once this function is defined then you simply need to execute a script that

    • Clears any variables named openvar
    • run the openVarWrapper script to setup the connection
    • point the original openVar to openVarWrapper

    Example Script:

    clear openvar;
    openVarWrapper;
    openvar = @openVarWrapper;
    

    Finally when you want to clean everything up you can simply call:

    clear openvar;
    
    0 讨论(0)
提交回复
热议问题