我发现自己一直在为数字运算编写相同的参数检查代码:
def myfun(a, b):
if a < 0:
raise ValueError('a cannot be < 0 (was a=%s)' % a)
# more if.. raise exception stuff here ...
return a + b
有更好的方法吗?我被告知不要对这些事情使用'断言'(虽然我没有看到问题,除了不知道导致错误的变量的值)。
编辑:为了澄清,参数通常只是数字,错误检查条件可能很复杂,非常重要,以后不一定会导致异常,而只是导致错误的结果。 (不稳定的算法,无意义的解决方案等)
答案 0 :(得分:4)
assert
(适度优化,但有时很高兴), python -O
会被优化掉。如果你有经常重复的模式,一个更好的选择可能是使用装饰器 - 分解重复的好方法。例如,假设您有许多函数必须使用参数by-position(而非by-keyword)调用,并且必须使其第一个参数为正;然后...
def firstargpos(f):
def wrapper(first, *args):
if first < 0:
raise ValueError(whateveryouwish)
return f(first, *args)
return wrapper
然后你会说:
@firstargpos def myfun(a,b): ...
并且一劳永逸地在装饰器(或者它返回的包装器闭包)中执行检查。因此,唯一棘手的部分是弄清楚你的函数需要什么检查以及如何最好地调用装饰器来表达那些(很难说,没有看到你定义的函数集和每个需要的检查集) ! - )。请记住,DRY(“不要重复自己”)接近软件开发指导原则中的第一位,Python有合理的支持,允许您实现DRY并避免使用样板,重复的代码! - )
答案 1 :(得分:0)
您不希望使用assert,因为您的代码可以运行(默认情况下在某些系统上),这样就不会检查断言行并且不会引发错误(-O
命令行标志)。
如果您使用了大量应该具有相同属性的变量,为什么不对您正在使用的任何类型进行子类化并将该检查添加到类本身?然后当你使用你的新课程时,你知道你从来没有一个无效的价值,并且不必在整个地方检查它。
答案 2 :(得分:-1)
我不确定这是否会回答你的问题,但是我觉得在函数开头检查很多参数并不是非常 pythonic 。
我的意思是,大多数pythonistas的假设是我们都同意成年人,我们彼此相信不要做一些愚蠢的事情。这是我写你的例子的方式:
def myfun(a, b):
'''a cannot be < 0'''
return a + b
这有三个明显的优点。首先,它很简洁,实际上没有额外的代码可以执行与您实际尝试完成的内容无关的任何操作。其次,它将信息准确地放在help(myfun)
中,其中pythonistas需要查找使用说明。最后,a
的非正值是否真的是一个错误?虽然你可能会这么认为,除非肯定会在a为零(这里可能不会)的情况下破坏,否则可能会让它滑过并导致调用流错误更明智。毕竟,如果a + b
出错,它会引发一个异常,它会在调用堆栈中向上传递,行为仍然几乎相同。