2009-04-28 62 views
108

Có thể có đối số mặc định trong Matlab không? Ví dụ: tại đây:Đối số mặc định trong Matlab

function wave(a,b,n,k,T,f,flag,fTrue=inline('0')) 

Tôi muốn có giải pháp thực sự là đối số tùy chọn cho hàm sóng. Nếu có thể, bất cứ ai có thể chứng minh cách thích hợp để làm điều này? Hiện tại, tôi đang thử những gì tôi đã đăng ở trên và tôi nhận được:

??? Error: File: wave.m Line: 1 Column: 37 
The expression to the left of the equals sign is not a valid target for an assignment. 

Cảm ơn!

Trả lời

139

Theo như tôi biết, không có cách nào trực tiếp để thực hiện việc này như bạn đã cố gắng.

Cách tiếp cận thông thường là sử dụng varargs và kiểm tra số lượng arg. Một cái gì đó như:

function f(arg1,arg2,arg3) 

    if nargin < 3 
    arg3 = 'some default' 
    end 

end 

Có một vài điều fancier bạn có thể làm với isEmpty, vv, và bạn có thể muốn nhìn vào matlab trung ương đối với một số gói bó những thứ như thế.

[cập nhật] vui vì điều đó đã giúp ích.

bạn có thể xem varargin, nargchk, v.v. chúng là các chức năng hữu ích cho loại điều này. varargs cho phép bạn để lại một số biến đối số cuối cùng, nhưng điều này không giúp bạn giải quyết vấn đề về các giá trị mặc định cho một số/tất cả chúng.

+3

Điều này đã hiệu quả! Cảm ơn! Đó là quá xấu mặc định đối số không thể được thực hiện thanh lịch hơn. – Scott

+12

@Scott: Đừng bao giờ nói những điều không thể làm được! Xem http://blogs.mathworks.com/pick/2010/04/02/setting-default-values/ –

+5

vẫn không thỏa mãn nếu so sánh với python hoặc mathematica – Leo

1

Số tiền này ít nhiều được nâng lên từ số Matlab manual; Tôi chỉ trải qua trải nghiệm ...

function my_output = wave (a, b, n, k, T, f, flag, varargin) 
    optargin = numel(varargin); 
    fTrue = inline('0'); 
    if optargin > 0 
    fTrue = varargin{1}; 
    end 
    % code ... 
end 
+1

Có một vài lỗi trong mã mà tôi đã sửa. Đầu tiên, "optargin" cần phải được xác định. Thứ hai, "varargin" là một mảng ô mà thu thập tất cả các đầu vào tiếp theo, vì vậy bạn phải sử dụng chỉ mục mảng ô để loại bỏ các giá trị từ nó. – gnovice

+0

Tôi cần kiểm tra thị lực; Tôi thề tôi không thấy điều đó trong cuốn cẩm nang ngày hôm qua: ( – kyle

+0

@ kyle: Đừng lo, tất cả chúng ta đều mắc lỗi. Đó là lý do tại sao tôi thích phong cách wiki-ish của SO: nếu tôi làm một số lỗi lầm ngớ ngẩn, thường có ai đó xung quanh có thể nắm bắt nó và sửa chữa nó một cách nhanh chóng cho tôi. =) – gnovice

10

Có, thật sự rất tuyệt khi có khả năng làm như bạn đã viết. Nhưng điều đó là không thể trong MATLAB. Nhiều người trong số các tiện ích của tôi cho phép giá trị mặc định cho các đối số có xu hướng được viết với kiểm tra rõ ràng ngay từ đầu như thế này:

if (nargin<3) or isempty(myParameterName) 
    MyParameterName = defaultValue; 
elseif (.... tests for non-validity of the value actually provided ...) 
    error('The sky is falling!') 
end 

Ok, vì vậy tôi thường sẽ áp dụng một thông báo lỗi tốt hơn, mô tả nhiều hơn. Thấy rằng việc kiểm tra biến trống cho phép người dùng chuyển vào một cặp ngoặc vuông trống, [], làm trình giữ chỗ cho một biến sẽ nhận giá trị mặc định của nó. Tác giả vẫn phải cung cấp mã để thay thế đối số trống đó bằng giá trị mặc định của nó. Các tiện ích của tôi phức tạp hơn, với các tham số MANY, tất cả đều có đối số mặc định, thường sẽ sử dụng giao diện cặp thuộc tính/giá trị cho các đối số mặc định. Mô hình cơ bản này được nhìn thấy trong các công cụ đồ họa xử lý trong MATLAB, cũng như trong tối ưu, odeset, v.v.

Như một phương tiện để làm việc với các cặp tài sản/giá trị này, bạn sẽ cần phải tìm hiểu về varargin. của việc nhập số lượng đối số đầy đủ vào một hàm. Tôi đã viết (và đăng) một tiện ích để làm việc với các cặp giá trị/thuộc tính như vậy, parse_pv_pairs.m. Nó giúp bạn chuyển đổi các cặp thuộc tính/giá trị thành một cấu trúc MATLAB. Nó cũng cho phép bạn cung cấp các giá trị mặc định cho mỗi tham số. Việc chuyển đổi một danh sách các tham số khó sử dụng thành một cấu trúc là một cách rất tốt để truyền chúng xung quanh trong MATLAB.

3

Tôi nhận thấy rằng chức năng parseArgs có thể rất hữu ích.

55

Tôi đã sử dụng đối tượng inputParser để xử lý cài đặt các tùy chọn mặc định.Matlab sẽ không chấp nhận các định dạng trăn giống như bạn chỉ định trong câu hỏi, nhưng bạn sẽ có thể để gọi hàm như thế này:

wave(a,b,n,k,T,f,flag,'fTrue',inline('0')) 

Sau khi bạn xác định wave chức năng như thế này:

function wave(a,b,n,k,T,f,flag,varargin) 

i_p = inputParser; 
i_p.FunctionName = 'WAVE'; 

i_p.addRequired('a',@isnumeric); 
i_p.addRequired('b',@isnumeric); 
i_p.addRequired('n',@isnumeric); 
i_p.addRequired('k',@isnumeric); 
i_p.addRequired('T',@isnumeric); 
i_p.addRequired('f',@isnumeric); 
i_p.addRequired('flag',@isnumeric); 
i_p.addOptional('ftrue',inline('0'),1);  

i_p.parse(a,b,n,k,T,f,flag,varargin{:}); 

Bây giờ các giá trị được chuyển vào hàm có sẵn thông qua i_p.Results. Ngoài ra, tôi đã không chắc chắn làm thế nào để xác nhận rằng các tham số thông qua trong cho ftrue đã thực sự là một chức năng inline vì vậy để trống validator.

+7

Tốt nhất tôi có thể nói, * this *, là phương pháp ưa thích. Nó sạch sẽ, tự tạo tài liệu (nhiều hơn như vậy là một loạt các 'nếu nargin' statemens), dễ bảo trì, nhỏ gọn và linh hoạt. – JnBrymn

1

Matlab không cung cấp cơ chế cho việc này, nhưng bạn có thể tạo một cơ chế trong mã người dùng dài hơn các trình nhập inputParser hoặc "if nargin < 1 ...".

function varargout = getargs(args, defaults) 
%GETARGS Parse function arguments, with defaults 
% 
% args is varargin from the caller. By convention, a [] means "use default". 
% defaults (optional) is a cell vector of corresponding default values 

if nargin < 2; defaults = {}; end 

varargout = cell(1, nargout); 
for i = 1:nargout 
    if numel(args) >= i && ~isequal(args{i}, []) 
     varargout{i} = args{i}; 
    elseif numel(defaults) >= i 
     varargout{i} = defaults{i}; 
    end 
end 

Sau đó, bạn có thể gọi nó trong các chức năng của bạn như thế này:

function y = foo(varargin) 
%FOO 
% 
% y = foo(a, b, c, d, e, f, g) 

[a, b, c,  d, e, f, g] = getargs(varargin,... 
{1, 14, 'dfltc'}); 

Định dạng là một quy ước cho phép bạn đọc xuống từ tên tham số giá trị mặc định của họ. Bạn có thể mở rộng getargs() với các thông số kiểu tham số tùy chọn (để phát hiện lỗi hoặc chuyển đổi ngầm) và phạm vi số đối số.

Có hai hạn chế đối với phương pháp này. Đầu tiên, nó chậm, vì vậy bạn không muốn sử dụng nó cho các hàm được gọi trong vòng lặp. Thứ hai, chức năng của Matlab giúp - các gợi ý tự động hoàn thành trên dòng lệnh - không hoạt động với các hàm varargin. Nhưng nó khá thuận tiện.

0

bạn có thể muốn sử dụng lệnh parseparams trong MATLAB; việc sử dụng sẽ như thế nào:

function output = wave(varargin); 
% comments, etc 
[reg, props] = parseparams(varargin); 
ctrls = cell2struct(props(2:2:end),props(1:2:end),2); %yes this is ugly! 
a = reg{1}; 
b = reg{2}; 
%etc 
fTrue = ctrl.fTrue; 
0
function f(arg1, arg2, varargin) 

arg3 = default3; 
arg4 = default4; 
% etc. 

for ii = 1:length(varargin)/2 
    if ~exist(varargin{2*ii-1}) 
    error(['unknown parameter: ' varargin{2*ii-1}]); 
    end; 
    eval([varargin{2*ii-1} '=' varargin{2*ii}]); 
end; 

ví dụ f(2,4,'c',3) làm cho thông số c là 3.

3

Ngoài ra còn có một 'hack' có thể được sử dụng mặc dù nó có thể được gỡ bỏ từ matlab tại một số điểm: Chức năng eval thực sự chấp nhận hai đối số trong đó thứ hai là chạy nếu một lỗi xảy ra với lần đầu tiên.

Như vậy chúng ta có thể sử dụng

function output = fun(input) 
    eval('input;', 'input = 1;'); 
    ... 
end 

sử dụng giá trị 1 như mặc định cho tham số

18

Một cách hơi ít hacky là

function output = fun(input) 
    if ~exist('input','var'), input='BlahBlahBlah'; end 
    ... 
end 
+0

Tùy chọn này không hoạt động nếu bạn định sử dụng MATLAB Coder để tạo mã C, vì Coder không hỗ trợ chức năng "tồn tại". –

2

Sau khi trở thành nhận thức ASSIGNIN (nhờ this answer bởi b3) và EVALIN Tôi đã viết hai hàm để cuối cùng có được một cấu trúc gọi rất đơn giản :

setParameterDefault('fTrue', inline('0')); 

Dưới đây là danh sách:

function setParameterDefault(pname, defval) 
% setParameterDefault(pname, defval) 
% Author: Tobias Kienzler (https://stackoverflow.com/users/321973) 
% sets the parameter NAMED pname to the value defval if it is undefined or 
% empty 

if ~isParameterDefined('pname') 
    error('paramDef:noPname', 'No parameter name defined!'); 
elseif ~isvarname(pname) 
    error('paramDef:pnameNotChar', 'pname is not a valid varname!'); 
elseif ~isParameterDefined('defval') 
    error('paramDef:noDefval', ['No default value for ' pname ' defined!']); 
end; 

% isParameterNotDefined copy&pasted since evalin can't handle caller's 
% caller... 
if ~evalin('caller', ['exist(''' pname ''', ''var'') && ~isempty(' pname ')']) 
    callername = evalin('caller', 'mfilename'); 
    warnMsg = ['Setting ' pname ' to default value']; 
    if isscalar(defval) || ischar(defval) || isvector(defval) 
     warnMsg = [warnMsg ' (' num2str(defval) ')']; 
    end; 
    warnMsg = [warnMsg '!']; 
    warning([callername ':paramDef:assigning'], warnMsg); 
    assignin('caller', pname, defval); 
end 

function b = isParameterDefined(pname) 
% b = isParameterDefined(pname) 
% Author: Tobias Kienzler (https://stackoverflow.com/users/321973) 
% returns true if a parameter NAMED pname exists in the caller's workspace 
% and if it is not empty 

b = evalin('caller', ['exist(''' pname ''', ''var'') && ~isempty(' pname ')']) ; 
2

Tôi tin rằng tôi tìm thấy khá một cách thuận tiện để đối phó với vấn đề này, chiếm chỉ có ba dòng mã (trừ dòng kết thúc tốt đẹp). Nội dung sau được gỡ bỏ trực tiếp từ một hàm tôi đang viết và có vẻ như hoạt động như mong muốn:

defaults = {50/6,3,true,false,[375,20,50,0]}; %set all defaults 
defaults(1:nargin-numberForcedParameters) = varargin; %overload with function input 
[sigma,shifts,applyDifference,loop,weights] = ... 
    defaults{:}; %unfold the cell struct 

Chỉ nghĩ rằng tôi muốn chia sẻ nó.

2

Tôi bối rối không ai đã chỉ ra this blog post bởi Loren, một trong những nhà phát triển của Matlab. Cách tiếp cận dựa trên varargin và tránh tất cả những trường hợp vô tận và đau đớn if-then-else hoặc switch trường hợp có điều kiện phức tạp. Khi có một vài giá trị mặc định là, hiệu ứng là ấn tượng. Dưới đây là ví dụ từ blog được liên kết:

function y = somefun2Alt(a,b,varargin) 
% Some function that requires 2 inputs and has some optional inputs. 

% only want 3 optional inputs at most 
numvarargs = length(varargin); 
if numvarargs > 3 
    error('myfuns:somefun2Alt:TooManyInputs', ... 
     'requires at most 3 optional inputs'); 
end 

% set defaults for optional inputs 
optargs = {eps 17 @magic}; 

% now put these defaults into the valuesToUse cell array, 
% and overwrite the ones specified in varargin. 
optargs(1:numvarargs) = varargin; 
% or ... 
% [optargs{1:numvarargs}] = varargin{:}; 

% Place optional args in memorable variable names 
[tol, mynum, func] = optargs{:}; 

Nếu bạn vẫn không hiểu, hãy thử đọc toàn bộ bài đăng trên blog của Loren. Tôi đã viết theo dõi blog post đề với thiếu giá trị mặc định vị trí. Tôi có nghĩa là bạn có thể viết một cái gì đó như:

somefun2Alt(a, b, '', 42) 

và vẫn có giá trị mặc định eps cho tol tham số (và @magic gọi lại cho func tất nhiên). Mã của Loren cho phép điều này với một sự sửa đổi nhỏ nhưng phức tạp.

Cuối cùng, chỉ là một vài ưu điểm của phương pháp này:

  1. Thậm chí với rất nhiều giá trị mặc định mã soạn sẵn không nhận được rất lớn (như trái ngược với gia đình của if-then-else cách tiếp cận, trong đó có được lâu hơn với mỗi mới giá trị mặc định)
  2. Tất cả các giá trị mặc định ở cùng một nơi. Nếu bất kỳ ai trong số những người cần thay đổi, bạn chỉ có một nơi để xem xét.

Cần lưu ý rằng, cũng có bất lợi. Khi bạn gõ chức năng trong trình bao Matlab và quên các tham số của nó, bạn sẽ thấy một số varargin không hữu ích như một gợi ý. Để đối phó với điều đó, bạn nên viết một mệnh đề sử dụng có ý nghĩa.

+0

Liên kết tới bài đăng blog tiếp theo của bạn bị hỏng; bạn có thể sửa nó không? – equaeghe

0

nếu bạn sẽ sử dụng quãng tám bạn có thể làm điều đó như thế này - nhưng thật đáng buồn matlab không hỗ trợ khả năng này

function hello (who = "World") 
    printf ("Hello, %s!\n", who); 
endfunction 

(lấy từ doc)

5

Đây là cách đơn giản của tôi để thiết lập giá trị mặc định đối với một hàm, sử dụng "try":

function z = myfun (a,varargin) 

%% Default values 
b = 1; 
c = 1; 
d = 1; 
e = 1; 

try 
    b = varargin{1}; 
    c = varargin{2}; 
    d = varargin{3}; 
    e = varargin{4}; 
end 

%% Calculation 
z = a * b * c * d * e ; 
end 

Kính trọng!

Các vấn đề liên quan