TryFoo应该抛出异常吗?(Should TryFoo ever throw an exception?)
.NET Framework中的一个常见模式是TryXXX模式(我不知道这是他们真正称之为的模式),其中被调用的方法尝试执行某些操作,如果成功则返回
True
,如果操作失败则返回False
。 一个很好的例子是通用的Dictionary.TryGetValue
方法。这些方法的文档说他们不会抛出异常:该失败将在方法返回值中报告。 迄今为止都很好。
最近我遇到了两种不同的情况,实现TryXXX模式的.NET Framework方法会引发异常。 请参阅System.Random构造函数中的错误? 和Uri.TryCreate抛出UriFormatException? 了解详情。
在这两种情况下,
TryXXX
方法都会调用其他引发意外异常的方法,并且这些异常会被转义。 我的问题:这是否打破了不抛出异常的暗示合同?换句话说,如果你正在写
TryFoo
,你会保证异常无法逃避吗?public bool TryFoo(string param, out FooThing foo) { try { // do whatever return true; } catch { foo = null; return false; } }
这很诱人,因为这样可以保证没有例外可以逃脱,从而履行隐含的合同。 但它是一个错误隐藏者。
根据我的经验,我的直觉表示这是一个非常糟糕的主意。 但是如果
TryFoo
允许一些异常逃逸,那么它真正的意思是“我不会抛出任何我知道如何处理的异常”,然后就抛出了合同“我不会抛出异常”的全部想法窗户。那么,你有什么看法?
TryFoo
应该处理所有的异常,还是只处理所期望的异常? 你的推理是什么?A common pattern in the .NET Framework is the TryXXX pattern (I don't know if that's what they really call it), in which the called method attempts to do something, returning
True
if it was successful, orFalse
if the operation failed. A good example is the genericDictionary.TryGetValue
method.Documentation for these methods say that they will not throw exceptions: that failure will be reported in the method return value. All good so far.
I recently encountered two different circumstances in which .NET Framework methods that implement the TryXXX pattern threw exceptions. See Bug in System.Random constructor? and Uri.TryCreate throws UriFormatException? for details.
In both cases, the
TryXXX
method called other methods that threw unexpected exceptions, and those exceptions escaped. My question: does this break the implied contract of not throwing exceptions?Put another way, if you were writing
TryFoo
, would you guarantee that exceptions cannot escape, by writing it like this?public bool TryFoo(string param, out FooThing foo) { try { // do whatever return true; } catch { foo = null; return false; } }
It's tempting, because that guarantees no exceptions will escape, thereby honoring the implied contract. But it's a bug hider.
My gut feeling, based on my experience, says that this is a really bad idea. But if
TryFoo
lets some exceptions escape, then what it's really saying is, "I won't throw any exceptions that I know how to handle," and then the whole idea of the contract "I won't throw exceptions" is thrown out the window.So, what's your opinion? Should
TryFoo
handle all exceptions, or just those that it's expecting to happen? What's your reasoning?
原文:https://stackoverflow.com/questions/1166880
最满意答案
parser
在解析时维护一个seen_actions
集对象(在_parse_known_args
方法中)。 在解析结束时,它会根据所需参数(具有required=True
那些参数)检查此集合,并可能发出错误。 变化也用于互斥组。但是这个变量在该函数之外是不可用的。 因此,缺少某种可以让你在
parse_args
动作中应用自己的测试的'钩子',你最好的选择就是测试默认值。 或者你可以看看sys.argv[1:]
。默认的
default
是None
。 这对于这个目的很好,因为你的用户不能给这个值。 也就是说,没有字符串可以转换为None
(至少不在任何常规type
方法中)。parser.add_argument('--foo') # default=None ... if args.foo is None: # clearly foo has not been specified. args.foo = 'the real default' else: # foo was specified pass
The
parser
maintains aseen_actions
set object while parsing (in the_parse_known_args
method). At the end of parsing it checks this set against the required arguments (ones withrequired=True
), and may issue a error. A variation is also used with mutually exclusive groups.But this variable is not available outside of that function. So short of some sort of 'hook' that lets you apply your own tests within the
parse_args
action, your best option is to test defaults. Or you can look atsys.argv[1:]
.The default
default
isNone
. That is nice for this purpose because your user cannot give this value. That is, there's no string that converts toNone
(at least not in any of the normaltype
methods).parser.add_argument('--foo') # default=None ... if args.foo is None: # clearly foo has not been specified. args.foo = 'the real default' else: # foo was specified pass
相关问答
更多-
实际上这很容易。 你只需要编写一个函数来检查文件是否有效,否则写入错误。 通过type选项使用该功能。 请注意,您可以更加喜欢并通过argparse.Action创建自定义操作,但我不认为这是必要的。 在我的例子中,我返回一个打开的文件句柄(见下文): #!/usr/bin/env python from argparse import ArgumentParser import os.path def is_valid_file(parser, arg): if not os.path.ex ...
-
parser在解析时维护一个seen_actions集对象(在_parse_known_args方法中)。 在解析结束时,它会根据所需参数(具有required=True那些参数)检查此集合,并可能发出错误。 变化也用于互斥组。 但是这个变量在该函数之外是不可用的。 因此,缺少某种可以让你在parse_args动作中应用自己的测试的'钩子',你最好的选择就是测试默认值。 或者你可以看看sys.argv[1:] 。 默认的default是None 。 这对于这个目的很好,因为你的用户不能给这个值。 也就是说, ...
-
正如你所说,参数w在命令行上期待-w之后的值。 如果您只是通过设置一个变量True或False来翻转开关,请查看http://docs.python.org/dev/library/argparse.html#action (具体来说store_true和store_false) parser.add_argument('-w', action='store_true') 编辑:正如斯文指出的,这种情况下的默认值是多余的。 As you have it, the argument w is expecti ...
-
标准文档没有提到FileAction 。 相反,有一个类FileType用于type参数,而不是用于action 。 所以我会写这样的东西: DEFAULT_START_CONFIG='/tmp/config.json' parser = argparse.ArgumentParser(description='Start the Cos service and broker for development purposes.') parser.add_argument('-c', '--config', ...
-
我不认为有一种使用argparse的原生方法,但幸运的是, argparse提供了报告自定义错误的方法。 最优雅的方式可能是定义一个自定义操作来检查重复项(如果存在则退出)。 class UniqueStore(argparse.Action): def __call__(self, parser, namespace, values, option_string): if getattr(namespace, self.dest, self.default) is not None ...
-
只需设置默认值即可。 如果未设置变量,则用户未传递该变量。 检查完毕后,您可以自己处理默认值。 The answers and comments here recommended to not set defaults, and then handle the defaults on my own within the code. However, the add_argument calls aren't completely under my control, so this wasn't really ...
-
这是你可能想要的: http://docs.python.org/library/argparse.html#sub-commands 有了这个,你可以添加具有自己的参数方案的子参数。 This is what you probably want: http://docs.python.org/library/argparse.html#sub-commands With this you can add sub arguments which have their own argument schemes ...
-
我如何使用Python的argparse命令行参数-h?(How can I have a command-line argument -h with Python's argparse?)[2023-09-11]
ArgumentParser采用可选参数add_help ,您可以设置False 。 在add_help的文档中: 偶尔,禁用此帮助选项可能会有用。 这可以通过将False作为add_help=参数传递给ArgumentParser : >>> parser = argparse.ArgumentParser(prog='PROG', add_help=False) >>> parser.add_argument('--foo', help='foo help') >>> parser.print_he ... -
有点晚了但是对于那些与OP有类似请求的人,你可以使用自定义的HelpFormatter 。 class ArgFormatter(argparse.HelpFormatter): def _format_args(self, *args): result = super(ArgFormatter, self)._format_args(*args) return result and '%%%' + result def _format_actions_us ...
-
argparse模块默认执行此操作。 看一下这个例子,我们指定两次相同的标志,最后一个获胜: import argparse parser = argparse.ArgumentParser(description='example') parser.add_argument('-a', '--add') options = parser.parse_args(['-a', 'foo', '-a', 'bar']) print 'add = {}'.format(options.add) # output: ...