我希望能够以编程方式更改匿名函数,例如将所有加号更改为函数中的乘号。在许多情况下,这个例子可以按如下方式完成:
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
将更改为任何输入错误的函数。
所以我的问题是是否可以从函数句柄中提取工作区并将其保留在创建的新函数句柄中?我需要以编程方式执行此操作,最好不使用内置函数functions
!
答案 0 :(得分:5)
一个简单的实现是将str2func
替换为eval
,这样您就不会遇到str2func
不允许访问本地变量的障碍。我们可以使用functions
来获取输入函数句柄的工作空间信息。
例如:
a = 5;
f = @(x) x+a;
finfo = functions(f)
收率:
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
是包含结构(来自MathWorks ...)的单元格数组,其中包含函数句柄名称空间中的所有变量:
>> wspace = finfo.workspace{1}
wspace =
struct with fields:
a: 5
使用此功能,天真的解决方案是遍历此工作空间中的变量,在changefunction
的命名空间中分配它们,然后使用eval
生成新的函数句柄。
例如:
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
任意执行传递给它的所有代码,所以它可以是非常危险的函数,必须谨慎使用。functions
的文档警告不要以编程方式使用它,因此在MATLAB版本更改时请注意检查行为:使用
functions
功能仅用于查询和调试。注意:不要以编程方式使用函数,因为它的行为可能会在后续的MATLAB®版本中发生变化。
答案 1 :(得分:2)
一种可行的方法是将函数句柄保存到.mat
文件(使用-v7.3
标志,以便创建一个易于修改的HDF5文件),修改{{1}在包含匿名函数的工作空间数据的文件中(使用MATLAB中内置的HDF5工具),然后从文件中再次加载匿名函数。
这是一个小功能,它完全正确(并且适用于相对简单的变量类型)
struct
您可以像以下一样使用它:
function result = modifyfunc(f, varname, value)
% modifyfunc - Modify the workspace of an anonymous function
%
% INPUTS:
% f: Function Handle, Anonymous function to modify
% varname: String, Name of the variable to modify
% value: Data to replace the specified variable
% If the value is a struct, recursively modify the function handle
if isstruct(value)
fields = fieldnames(value);
result = f;
% Modify each field separately
for k = 1:numel(fields)
% Append the fieldname to the variable name and modify
name = [varname, '.', fields{k}];
result = modifyfunc(result, name, value.(fields{k}));
end
return;
end
% Write the anonymous function to an HDF5 file
fname = tempname;
save(fname, 'f', '-mat', '-v7.3');
% Replace any "." in the variable name with "/" to construct the HDF5 path
varname = strrep(varname, '.' , '/');
% Now modify the data in the file
h5write(fname, ['/#refs#/e/' varname], value);
% Load the modified function handle from the file
result = load(fname, '-mat');
result = result.f;
% Remove the temporary file
delete(fname);
end
一些警告包括:
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
数组。