matlab - access variable in specific workspace

孤人 提交于 2019-12-11 03:47:42

问题


I need something similar to evalin, but original evalin of Matlab cannot be used recursively. For example, I have function f0 which calls 2 other functions f11 and f12:

function f0()
    [v1, v2] = deal(1, 1);

    f11();
    f12();

    disp(v1);
end

Functions f11 and f12 use variable v1, and both call function f2:

function f11()
    v1 = evalin('caller', 'v1');

    f2();

    assignin('caller', 'v1', v1);
end

function f12()
    v1 = evalin('caller', 'v1');

    f2();

    assignin('caller', 'v1', v1);
end

And the function f2 should use both variables v1 and v2 of f0's workspace:

function f2()
    v1 = evalin('caller', 'v1');    % get variable v1 from f11 or f12
                                    % since there is already a variable v1 
                                    % in f11 and f12's workspaces
    % TODO: get v2 from f0

    if v2 == 1
        v1 = v1 + 1;
    end

    assignin('caller', 'v1', v1);

end

Is there anyway to make the TODO possible without using v2 = evalin('caller', 'v2') in f11 and f12 ?


回答1:


This is possibly one of the worst way of organising your data transfer between functions. Workspaces of functions are separated for a good reason, to keep things clean and organised.

You are trying to bypass all safeguards put in place by people who designed this language (and many other language who share this separation of workspace/scope). These "bypass" functions are available in Matlab for punctual usage when you are prototyping. They are not intended for heavy usage or for final solution (most of them won't be compilable actually).

It is

  • potentially ultra confusing (for you later on, but even worse if someone else has to use your code).
  • very hard to debug (you almost have to know the value of a variable in advance to know if the import from another workspace was right).

You say in the comment that passing variable as parameter is complicated because of their number, but every time you call something like x = evalin('caller', 'x'); you have to write 1 full line of code to retrieve your value anyway. And then assignin('caller', 'x', x); is another line of code to send it back ... that's madness.

Would it not be simpler (and shorter) to just have x in your function input parameters ?? (it is still faster to have 100 variables in input than to have 200 full lines of codes to retrieve then resend these values from uncertain locations).


Recommended (if practical): pass variable in parameter

To make variable passing easy you could for example gather them all in a structure (or a cell array):

[v1, v2] = deal(1, 1);
myVars.v1 = v1 ;
myVars.v2 = v2 ;

myVars = f11(myVars); %// you only have one variable to pass into your functions
myVars = f12(myVars); %// just make sure you retrieve it in output too

disp(myVars.v1);

And then

function myVars = f11()
    myVars = f2(myVars);
end

And so on, as long as you pass the variable to the next function, then retrieve it in output, this would work with any level of recursion.


Recommended (if above not possible): Use nested functions

If you define your function f11() inside your f0(), the variable which have the same name in the 2 functions will be shared (visible by at both levels). Read the documentation for more detail. This way you would not need your numerous call to evalin/assignin because the variable is know everywhere. Your function would have to be written in this form:

function f0()
[v1, v2] = deal(1, 1);

f11();
f12();

disp(v1);

    function f11()
        f2();
        function f2()
            if v2 == 1
                v1 = v1 + 1;
            end
        end
    end %// END function F11

    function f12()
        f2();
        function f2()
            if v2 == 1
                v1 = v1 + 1;
            end
        end
    end %// END function F12

end %// END function F0

Stack Exchange does not render that, but in the Matlab editor you could notice that the "shared" variable will be highlighted in a different colour (to alert you that they have a different scope than standard variable).

If I run f0() I do get:

>> f0
     3

Which was the expected result. The only downside, as you can see, is that if you are calling f2() from within f11() and f12(), the function f2() has to be written within each of them (so a bit of copy/paste). Unless at this level of recursion you do not have too many variable to pass so you could consider writing f2() on the side and using the standard variable passing scheme.


Can work, but not recommended

Now if you are still keen on writing numerous lines of codes just to pass single variables around, there are still 2 options:

  • use global variables
  • use setappdata and getappdata

I do not like to use global so I won't detail here. Just remember that for a variable to be really global it has to be declared as global in every function where it is used.

For the appdata method, you need a "container" which will be accessible to all your functions. You can use the "root" object for that (identifier: 0).

So for example, when you want to store a variable you could use:

setappdata( 0 , 'v2' , v2 ) %// store the value of `v2` in a field named `'v2'` in the root object.

then in any of your function, get the value, work on it then store it back:

function f2()
    v1 = getappdata(0,'v1')     %// get the value of v1
    v2 = getappdata(0,'v2')     %// get the value of v2
    if v2 == 1
        v1 = v1 + 1;            %// modify the value of v1
    end
    v1 = setappdata(0,'v1',v1)  %// store the value of v1
end

Apply the same principle in your base function and f11(), f12(), etc ... Just remember to always store any value back after you modified it so it is available for the next function which will need it.




回答2:


Just trying to get this right: Your 'Variables' are holding a value that should be consistent over operations that you like to perform on them. Only a shot in the dark, but have you tried Object-Orientation on your problem.

classdef myObj
properties
    v1;
    v2;
end
methods
    function f1(obj)
        ... do something here ....
        obj.v1 = ....;
    end
    function f2(obj)
        obj.f1();
    end
end

Depending on your specific problem this might be the easiest way to get recursion right. OO in Matlab isnt that hard to learn.

Hth




回答3:


You can save f0()'s variables to a file and then call a load method in f2() to import those variables in f2() workspace.



来源:https://stackoverflow.com/questions/28081836/matlab-access-variable-in-specific-workspace

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!