如何在MATLAB中设定哨兵值? [英] How to make a sentinel value in MATLAB?
问题描述
下面的示例在Python中可能有助于说明警戒值"的含义:
The following example, in Python, may help illustrate what I mean by a "sentinel value":
SENTINEL = object()
def foo(opt=SENTINEL):
if opt is SENTINEL:
opt = make_me_fresh_default_opt_please()
# etc
在变量SENTINEL
上方的代码段中,初始化为一个全新的"nonce"对象,该对象实际上没有任何内容,并且在定义该文件的文件之外的其他任何地方都没有可能的含义. foo
是一个带有可选参数opt
的函数.常量SENTINEL
由foo
用于一件事和仅一件事:测试无参数调用的条件.这是通过if opt is SENTINEL
完成的.
In the snippet above the variable SENTINEL
is initialized to a brand new "nonce" object, one that has, as it were, no content, and no conceivable meaning anywhere else outside the file where it is defined. foo
is a function that takes an optional argument, opt
. The constant SENTINEL
is used by foo
for one thing and one thing only: to test the condition of being called with no arguments. This is done with if opt is SENTINEL
.
要了解为什么要使用像SENTINEL
这样的廉价"nonce"常量,请将上面的代码段与使用标准Python值(None
)来测试无参数条件的内容进行对比:
To see why one would want such a cheap, "nonce" constant like SENTINEL
, contrast the snippet above with one that uses a standard Python value (None
) to test the no-argument condition:
def foo2(opt=None):
if opt is None:
opt = make_me_fresh_default_opt_please()
# etc
此函数foo2
不能区分下面的两个调用 1 :
This function foo2
cannot distinguish between the two calls below1:
foo2()
foo2(None)
因此,总而言之,这里的前哨"是指其余代码未知的常量值,其唯一目的是用作某种条件下布尔测试的基础.
So, in sum, by "sentinel" here I mean a constant value that is unknown to the rest of the code, and whose only purpose is to serve as the basis for a boolean test for some condition.
在MATLAB中是否有类似的简单方法来生成这样的定点常量?
Is there a similarly simple way to generate such a sentinel constant in MATLAB?
我想强调一点,我的问题严格来说是关于如何创建一个哨兵的问题,而未提及使用此类哨兵的目的的问题.我提供了一个具体而合理的示例,说明为什么有人想要这样一个定点常量,部分目的是确保该帖子的读者知道我所说的哨兵"一词的含义.在此示例中,前哨恰好发生用于测试无参数传递"条件,但是还有许多其他可能的条件需要使用前哨值进行测试.因此,这个问题着重不是测试无参数传递"条件,而是一般而言,生成哨兵常量的问题.
I want to stress that my question is strictly about how to create a sentinel, leaving open the issue of the purpose to which such sentinel would be used. I provided a concrete and plausible example of why one may want such a sentinel constant, in part to make sure that readers of the post would know what I meant by the word "sentinel". In this example, the sentinel just happens to be used to test for a "no argument passed" condition, but there are countless other possible conditions that one may want to test using a sentinel value. So, this question is, emphatically, not about testing for a "no argument passed" condition, but about the problem of generating sentinel constants, in general.
基于Notlikethat's和Bas Swinckels的答案:
based on Notlikethat's and Bas Swinckels's answers:
function y = foo(varargin)
p = inputParser;
p.addParameter('Opt', @DEFAULT);
p.parse(varargin{:});
opt = p.Results.Opt;
if DEFAULT(opt)
opt = rand();
end
y = opt;
% etc
end
function its_me = DEFAULT(opt)
its_me = isequal(opt, @DEFAULT);
end
%{
>> foo('Opt', 3)
ans =
3
>> foo()
ans =
0.9134
>> foo
ans =
0.6324
%}
好的,那可能太可爱了.如果代码更接近Notlikethat的原始建议(请注意,下面的make_sentinel
是一个独立的函数),则该代码既简单又清晰:
OK, that's maybe too-cute-by-half. The code is both simpler and clearer if it stays closer to Notlikethat's original suggestion (note that make_sentinel
below is a free-standing function):
% foo.m
function y = foo(varargin)
DEFAULT = make_sentinel();
p = inputParser;
p.addParameter('Opt', DEFAULT);
p.parse(varargin{:});
opt = p.Results.Opt;
if isequal(opt, DEFAULT)
opt = rand();
end
y = opt;
% etc
end
% make_sentinel.m
function sentinel = make_sentinel()
sentinel = ...
@() 'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_function';
% or, more conventionally,
% sentinel = @() 0;
end
>> foo('Opt', 6)
ans =
6
>> foo()
ans =
0.9575
>> foo
ans =
0.9649
并且要证明make_sentinel
产生的哨兵确实是独一无二的(而且反常不会付出代价):
And to show that the sentinels produced by make_sentinel
are indeed unique (and that perversity won't pay):
>> foo('Opt', make_sentinel())
ans =
@()'qqqxyz_lalala_the_user_would_be_a_moron_to_use_this_function'
1 当然,前面定义的foo
不能区分foo()
和foo(SENTINEL)
,但是,AFAIC,像后者一样的调用属于不正当"类别.编程"(因为它要求调用代码摆脱干扰"以颠覆被调用代码的意图),而且我不必担心这种麻烦.相反,前面显示的foo2(None)
示例说明了在例行编程过程中很容易发生的情况,尤其是当它的实际源代码类似于foo(some_variable)
且some_variable
意外地持有标准Python时值None
.
1 Of course, the foo
defined earlier cannot distinguish between foo()
and foo(SENTINEL)
, but, AFAIC, a call like the latter falls within the category of "perverse programming" (since it requires the calling code to "go out of its way" to subvert the called code's intentions), and I don't worry about such perversities. In contrast, the foo2(None)
example shown earlier illustrates a situation that could happen easily in the course of routine programming, especially when the actual source code for it is something like foo(some_variable)
, and some_variable
unintendedly ends up holding the standard Python value None
.
推荐答案
一个解决方案几乎是直接等效的:
One solution would be pretty much the direct equivalent:
function y = foo(opt)
%default argument
if nargin<1
opt = @SENTINEL;
end
%actual check
if isequal(opt, @SENTINEL)
opt = make_me_fresh_default_opt_please()
end
% etc
end
function SENTINEL % private function in the same file
end
当然不是那么简单,但这和其他任何东西一样,都取决于Matlab语法.
Admittedly not quite as simple, but that's as much down to Matlab syntax as anything else.
您可能还可以作弊,并以完全相同的方式基于 :
You could probably also cheat a bit and base it on exactly the same approach:
SENTINEL = java.lang.Object;
% etc...
为了更简单起见,牺牲保证的唯一性,tempname
是生成不太可能与有效数据发生冲突的字符串的一种简便方法(尤其是如果有效数据不是字符串的情况下...)
Sacrificing guaranteed uniqueness for even more simplicity, tempname
is an easy way to generate a string that's unlikely to collide with valid data (especially if valid data isn't strings...)
这篇关于如何在MATLAB中设定哨兵值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!