эквивалент `evalin`, который не требует выходного аргумента (внутренне) - PullRequest
2 голосов
/ 18 апреля 2019

Фон - я читал о доступе к теневым функциям и начал играть с builtin. Я написал небольшую функцию:

function klear(x)
%  go to parent environment...
evalin('base', builtin('clear','x')) ;  
end

Это выдает ошибку:

Error using clear
Too many output arguments.

Я думаю, это происходит потому, что evalin требует вывода из всего, что ему подают, но clear - это одна из функций, которая не имеет возвращаемого значения.
Итак, два вопроса: правильно ли я интерпретирую это, и если да, есть ли альтернативная функция, которая позволяет мне выполнять функцию в родительской среде (которая не требует вывода)?

Примечание: я полностью осведомлен об аргументах против попытки доступа к теневым функциям (или, скорее, чтобы избежать именования функций способом, который перегружает базовые функции и т. Д.). Это прежде всего вопрос, который поможет мне узнать, что можно и чего нельзя делать в MATLAB.

Примечание 2

Моя первоначальная цель состояла в том, чтобы написать функцию перегрузки, которая потребовала бы входной аргумент, чтобы избежать поведения вредоносного ПО clear, которое по умолчанию удаляет все. В псевдокоде Q & D,

function clear(x)
if ~exist('x','var') return
execute_in_base_env(builtin(clear(x)))
end

Ответы [ 2 ]

2 голосов
/ 19 апреля 2019

Есть пара проблем с вашим clear переопределением:

  • Он всегда будет clear в базовом рабочем пространстве независимо от того, откуда он вызывается.
  • Он не поддерживает несколько входов, что является распространенным вариантом использования для очистки.

Вместо этого я бы попросил его проверить, вызывается ли он из базовой рабочей области, и в особом случае, чтобы проверить, очищает ли он все. Если какая-то функция вызывает простой clear для очистки всех ее переменных, это плохая практика, но все равно работает логика этой функции, и вы не хотите ее нарушать. В противном случае это может привести к ошибке или, что еще хуже, вернуть неверные результаты.

Итак, как-то так:

function clear(varargin)
  stk = dbstack;
  if numel(stk) == 1 && (nargin == 0 || ismember('all', varargin))
    fprintf('clear: balking at clearing all vars in base workspace. Nothing cleared.\n');
    return;
  end

  % Check for quoting problems
  for i = 1:numel(varargin)
    if any(varargin{i} == '''')
      error('You have a quote in one of your args. That''s not valid.');
    end
  end
  % Construct a clear() call that works with evalin()
  arg_strs = strcat('''', varargin, '''');
  arg_strs = [{'''clear'''} arg_strs];
  expr = ['builtin(' strjoin(arg_strs, ', '), ')'];
  % Do it
  evalin('caller', expr);
end

Надеюсь, само собой разумеется, что это жестокий взлом, который я бы не рекомендовал на практике. :)

2 голосов
/ 18 апреля 2019

Что происходит в вашем коде:

evalin('base', builtin('clear','x'));

означает, что builtin оценивается в текущем контексте, и поскольку оно используется в качестве аргумента для evalin, ожидается, что он выдаст выходные данные. Это точно так же, как:

ans = builtin('clear','x');
evalin('base',ans);

Сообщение об ошибке, которое вы видите, появляется в первой из этих двух строк кода, а не во второй. Это не из-за evalin, который поддерживает операторы вызова, которые не создают выходной аргумент.

evalin требует строку для оценки. Вам нужно построить эту строку:

str = 'builtin(''clear'',''x'')';
evalin('base',ans);

(В MATLAB символ кавычки экранируется путем удвоения его.)

Ваша функция будет выглядеть так:

function clear(var)
try
    evalin('base',['builtin(''clear'',''',var,''')'])
catch
    % ignore error
end
end

(Вставка строки в другую строку таким образом довольно неловко, одна из многих причин, по которой мне не нравятся eval и друзья).

В этом случае может быть лучше использовать evalin('caller',...), чтобы при вызове нового clear из функции он удалял что-то в рабочем пространстве функции, а не в базовом. Я думаю, что 'base' следует использовать только из GUI, который, как ожидается, будет управлять переменными в рабочей области пользователя, а не из функции, которую можно вызывать где угодно и которая (в данном случае, по ее имени) будет делать что-то локальное.


Есть причины, по которым это может быть действительно полезным, но в целом вы должны стараться избегать использования clear так же, как использование eval и друзей. clear замедляет выполнение программы. Гораздо проще (как для пользователя, так и для MATLAB JIT) назначить пустой массив переменной, чтобы удалить ее содержимое из памяти (как предложено rahnema1 в комментарии . Ваше базовое рабочее пространство не будет забит переменными, если вы использовали function больше: пишите функции, а не скрипты!

...