Matlab 是否可以更改保留工作区的匿名函数?

Matlab 是否可以更改保留工作区的匿名函数?,matlab,anonymous-function,Matlab,Anonymous Function,我希望能够以编程方式更改匿名函数,例如,将函数中的所有加号更改为乘法符号。此示例在许多情况下都可以按如下方式执行: function f2 = changefunction(f1) fs = func2str(f1); fs(fs=='+') = '*'; f2 = str2func(fs); end 但是考虑例子 f = @(x) x+5; a = 5; g = @(x) x+a; f和g都是匿名函数,在插入的任何内容中添加5;但是,只有f会被changefunct

我希望能够以编程方式更改匿名函数,例如,将函数中的所有加号更改为乘法符号。此示例在许多情况下都可以按如下方式执行:

function f2 = changefunction(f1)
    fs = func2str(f1);
    fs(fs=='+') = '*';
    f2 = str2func(fs);
end

但是考虑例子

f = @(x) x+5;
a = 5;
g = @(x) x+a;
f
g
都是匿名函数,在插入的任何内容中添加5;但是,只有
f
会被
changefunction
功能正确更改,而
g
会被更改为任何输入都会出错的功能


所以我的问题是,是否可以从函数句柄中提取工作空间,并将其保留在创建的新函数句柄中?我需要以编程方式完成,最好不要使用内置函数
函数

一个简单的实现是替换为,这样您就不会遇到
str2func
不允许访问局部变量的障碍。我们可以使用获取输入函数句柄的工作空间信息

例如:

a = 5;
f = @(x) x+a;
finfo = functions(f)
function f2 = changefunction_new(f1)
    tmp = functions(f1);
    workspacevars = tmp.workspace{1};
    varnames = fieldnames(workspacevars);
    for ii = 1:length(varnames)
        evalstr = sprintf('%s = %d;', varnames{ii}, workspacevars.(varnames{ii}));
        eval(evalstr);
    end

    fs = func2str(f1);
    fs(fs=='+') = '*';
    f2 = eval(fs);
end
收益率:

finfo = 

  struct with fields:

            function: '@(x)x+a'
                type: 'anonymous'
                file: 'X:\testcode-matlab\testcode.m'
           workspace: {[1×1 struct]}
    within_file_path: 'testcode'
其中
workspace
是一个单元格数组,其中包含一个结构(come on MathWorks…),该结构包含函数句柄命名空间中的所有变量:

>> wspace = finfo.workspace{1}

wspace = 

  struct with fields:

    a: 5
使用此功能,最简单的解决方案是循环此工作区中的变量,在
changefunction
的命名空间中分配它们,然后使用
eval
生成新的函数句柄

例如:

a = 5;
f = @(x) x+a;
finfo = functions(f)
function f2 = changefunction_new(f1)
    tmp = functions(f1);
    workspacevars = tmp.workspace{1};
    varnames = fieldnames(workspacevars);
    for ii = 1:length(varnames)
        evalstr = sprintf('%s = %d;', varnames{ii}, workspacevars.(varnames{ii}));
        eval(evalstr);
    end

    fs = func2str(f1);
    fs(fs=='+') = '*';
    f2 = eval(fs);
end
这里我假设变量是严格的数字。如果情况并非总是如此,您可以添加逻辑来检查要生成的数据类

因此,我们有:

a = 5;
g = @(x) x+a;
test1 = changefunction(g);
test2 = changefunction_new(g);

>> g(1)

ans =

     6

>> test1(1)
Undefined function or variable 'a'.

Error in testcode>@(x)x*a

>> test2(1)

ans =

     5
尽管如此,最好的解决方案实际上是显式定义函数句柄。这可能会很痛苦,但更容易理解和调试


有几点需要注意:

  • 由于
    eval
    任意执行传递给它的所有代码,因此它可能是一个非常危险的函数,必须小心使用
  • 函数的文档
    警告不要以编程方式使用它,因此请注意检查MATLAB版本更改时的行为:
使用
函数
函数仅用于查询和调试目的

注意:不要以编程方式使用函数,因为其行为可能会在后续的MATLAB®版本中发生变化


一种可能的方法是将函数句柄保存到
.mat
文件中(使用
-v7.3
标志,以便创建易于修改的HDF5文件),修改包含匿名函数工作空间数据的文件中的
结构(使用MATLAB内置的HDF5工具),然后从文件中再次加载匿名函数

这里有一个小函数,它正好做到这一点(它适用于相对简单的变量类型)

你可以像这样使用它:

a = 1;
b = struct('field', 2);

f = @(x)disp(a + b.field + x);
f(10)
%   13

f2 = modifyfunc(f, 'a', 2);
f2(10)
%   14

f3 = modifyfunc(f2, 'b.field', 3);
f3(10)
%   15

b.field = 4;
f4 = modifyfunc(f3, 'b', b);
f4(10)
%   16
一些警告包括:

  • 替换数据必须与原始数据大小相同
  • 这依赖于.mat文件的格式,对于匿名函数,该文件完全没有文档记录,因此在将来的版本中可能会失败
  • 这目前不适用于函数工作区中
    cell
    数组的变量

为了获得轻微的额外安全余量,您可以将其重新加载。它仍然很脏,仍然使用
函数。