Фон - я читал о доступе к теневым функциям и начал играть с 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
Carl Witthoft 18 Апр 2019 в 14:27

2 ответа

Лучший ответ

Есть пара проблем с вашим 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
Andrew Janke 20 Апр 2019 в 10:37

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

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 больше: пишите функции, а не сценарии!

2
Andrew Janke 19 Апр 2019 в 09:06