函数multiply_by_ten
采用数字参数,将其乘以10并返回结果。
在此函数执行乘法运算之前,它会检查argument
是否为数字。如果argument
不是数字,则函数会打印出消息,通知参数不是数字并返回None。
问题即可。一些开发人员认为,无论情况如何,任何给定的函数都应该返回相同类型的值。所以,如果我遵循这样的意见,那么这个函数不应该返回None。如何处理这样的情况?在将参数发送到函数之前是否应该检查参数?为什么呢?
def multiply_by_ten(arg):
if not str(arg).isdigit():
print 'arg is not a digit'
return
return float(arg) * 10
result = multiply_by_ten('abc')
答案 0 :(得分:22)
我写这个函数有很多问题。
它做了两件非常不同的事情:要么做一些数学并返回一个有用的答案,要么打印一条消息。这已经引发了一些危险信号。
它会向stdout
输出错误。实用程序代码应尽可能避免打印,但永远不会向stdout
投诉。这属于应用程序,而不是虚假错误。
如果效用函数需要投诉并且没有其他方法可以执行此操作,请使用stderr
作为最后的手段。 (但在Python中,你有例外和警告,所以肯定有另一种方法可以做到这一点。)当然,打印调试很好 - 只需确保在完成后删除它。 :)
如果出现问题,来电者不知道是什么。它得到了None
,但这并没有真正解释问题;解释归于一个对此无能为力的人。
编写正确使用此函数的代码也很困难,因为您可能会得到一个或的数字,可能会得到None
- 并且因为您只能得到None
输入是假的,人们往往不会过多地考虑失败案例,你最终可能会编写代码来假设一个数字回来。
有时候返回不同类型的值会很有用,但返回一个可以是有效值的值或一个错误指示符总是一个坏主意。它正确处理起来比较困难, 正确处理它的可能性更小,而且正是异常要解决的问题。
首先没有理由成为一个功能!错误检查是float()
已经提供的重复工作,并且乘以10不是一个需要将其考虑在内的常见操作。实际上,这会使调用代码更长。
所以我会放弃这个函数并写下来:
result = float('abc') * 10
奖励:任何Python程序员都会识别float
,知道它可能会引发ValueError
,并且知道在必要时添加try
/ except
。
我知道这可能是书籍或家庭作业中的一个人为例子,但这就是为什么考虑具有琐碎的例子的架构并不真正有效 - 如果你真的认真对待它,整个例子往往会消失。 :)
答案 1 :(得分:14)
如果作者认为函数应该只返回一种类型(None实际上不是返回值,则在大多数情况下缺少一种),在这种情况下,正确的答案是抛出异常。 IMO使用EAFP原则的正确逻辑是:
def multiply_by_ten(arg):
return float(arg) * 10
try:
result = multiply_by_ten('abc')
except ValueError:
pass
我也不建议重复标准库已经为您做的事情,因为您自己的实现通常比已经为您做的更糟糕。例如:
>>> "0.01e-6".isdigit()
False
>>> float("0.01e-6")
1e-8
如果函数已经检查了传递的参数的有效性,并在失败时抛出异常,则不需要仔细检查它。
最后,我认为函数应返回单一类型的想法是危险的:异常处理很好,因此返回无效标志,但Python是一种动态语言,原因是:它允许设计多态。在合理的范围内使用它。
最后,有点透视。在C ++中,一种静态类型语言,可能存在任意,可选,并集和变体的千种不同实现,所有这些实现都旨在将多个类型保存在同一容器中。即使在静态类型语言中,多态也很有用。如果使用sparing,则多态性是语言的一个有用特性。
答案 2 :(得分:9)
在Python中处理错误的常见做法不是返回与预期值类型不同的值,而是通过引发异常。
正如@AGN Gazer指出的那样,通过捕捉错误演员的异常,你会更快,避免你做一个简单的乘法函数:
try:
result = float('abc') * 10
except:
print('Error: not a valid number')
如果我们保留旧的代码结构,而不是:
def multiply_by_ten(arg):
if not str(arg).isdigit():
print 'arg is not a digit'
return
return float(arg) * 10
你应该这样做:
def multiply_by_ten(arg):
if not str(arg).isdigit():
raise Exception('NotNumber', 'The argument is not a number')
# Do some other stuff? Otherwise not really helpful
return float(arg) * 10
在你的电话中:
try:
result = multiply_by_ten('abc')
catch Exception as e:
if e.args[0] == 'NotNumber':
print('Error: '+e.args[1])
else:
raise
答案 3 :(得分:5)
如果您总是期待某个号码会引发exception
,则表示存在问题。
如果值可能丢失且与程序逻辑没有任何冲突,则返回None
。
最重要的是代码一致性 - 您在代码的其他位置做了什么?
答案 4 :(得分:1)
任意决定说任何给定的函数应该只返回一种类型的值就是:任意。
在这种情况下,因为您返回的是数值,而不使用None
或表示发生问题的字符串,您将被限制为尝试返回一些数字以指示发生了问题:某些函数返回-1之类的数字作为出现问题的信号。但是,如果输入为-0.1,则在这种情况下不起作用。
正如你所说,如果你真的想要只返回一种类型的值(总是整数或总是浮动),那么除了事先检查之外我没有看到很多选项。
选项可能包括使用其他作者建议的try / except语句。
答案 5 :(得分:0)
这太傻了。函数始终只返回一种类型。如果该函数可以返回int
或None
,那么它就是和类型,特别是Optional[int]
。