【问题标题】:Checking arguments in numerical Python code检查数值 Python 代码中的参数
【发布时间】:2009-10-29 04:17:06
【问题描述】:

我发现自己一直在为数字运算编写相同的参数检查代码:

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

有没有更好的方法?我被告知不要对这些事情使用“断言”(尽管我没有看到问题,除了不知道导致错误的变量的值)。

edit:澄清一下,参数通常只是数字,错误检查条件可能很复杂,不平凡,以后不一定会导致异常,而只会导致错误的结果。 (不稳定的算法,无意义的解决方案等)

【问题讨论】:

  • 谁说不用assert?他们给出了什么理由?你能得到报价或参考吗?
  • @S.Lott:因为断言随着__debug__ 或优化以及“程序员的断言,用户的例外”的口头禅而消失。参考? err..我们称之为“私人通信”

标签: python exception arguments assert


【解决方案1】:

如果您使用python -O 运行,assert 会被优化掉(适度的优化,但有时很高兴)。如果您有经常重复的模式,那么一种更好的选择可能是使用装饰器——排除重复的好方法。例如,假设您有无数个函数,必须按位置(而不是按关键字)调用参数,并且它们的第一个参数必须为正;然后...:

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 并避免样板、重复的代码!-)

【讨论】:

  • 我认为他的用例会有所不同,但是包装器是否优于我对他的数据类型进行子类化的建议?
  • 强制每个调用者使用“子类化”数据类型对每个调用者来说都是高度侵入性的,并将函数的可重用性降低到一个危险的程度。装饰器只是表达每个函数需要的检查集的另一种方式(避免样板和重复),并且对调用者完全透明,这是一件非常好的事情。
  • 很公平。我假设他正在清理输入,然后将其传递给他的所有函数,因此子类数据类型将让他不必每次都重新运行该检查。
  • 不,我正在分别清理每个函数的输入,但装饰器很高兴为未来记住,干杯
【解决方案2】:

您不想使用断言,因为您的代码可以以不检查断言行并且不会引发错误(-O 命令行标志)的方式运行(并且默认情况下在某些系统上)。

如果您使用的许多变量都应该具有相同的属性,为什么不将您使用的任何类型子类化并将检查添加到类本身?然后当你使用你的新类时,你知道你永远不会有一个无效的值,也不必到处检查它。

【讨论】:

    【解决方案3】:

    我不确定这是否能回答你的问题,但令我震惊的是,在函数开头检查很多参数并不是很pythonic

    我的意思是,大多数 pythonistas 都假设我们都是同意的成年人,并且我们彼此信任不会做愚蠢的事情。这是我写你的例子的方式:

    def myfun(a, b):
        '''a cannot be < 0'''
        return a + b
    

    这具有三个明显的优势。首先,它很简洁,实际上没有额外的代码做任何与你实际想要完成的事情无关的事情。其次,它将信息准确地放在它所属的位置,在help(myfun),pythonistas 应该在其中查找使用说明。最后,a 的非正值真的是错误吗?尽管您可能会这样认为,除非如果 a 为零(这里可能不会),除非某些东西肯定会中断,那么也许让它溜过并导致调用流中的错误更明智。毕竟,如果a + b 出错,它会引发一个异常,该异常会被传递到调用堆栈并且行为仍然几乎相同。

    【讨论】:

    • 我不同意。如果您的函数比 a+b 更复杂,则负 a 性质的错误很可能会正确评估,但会返回不正确的结果。想想银行账户存款。我同意你应该只在适当的地方检查你的输入的有效性,但是假设 python 会为错误的数据抛出错误是危险的。 “显式优于隐式”!
    • @Paul McMillan:在银行交易的背景下,“成年人同意”的假设也可能是无效的。相反,我更希望我的银行机构假设与之互动的每个人都是儿童或罪犯或两者兼而有之。
    • 我不同意。如果您事先知道否定参数是错误的,请检查对函数的调用并立即引发异常。它可能是错误的,不会导致异常;它可能是错误的并导致一个奇怪的、令人困惑的异常;它可能是错误的,并且会破坏一些东西,随后数千行代码会引发异常,因此确实非常令人困惑。 (我相信,“同意成年人”的说法最初是指无法阻止人们自省私有变量的抱怨,在这种情况下,我同意。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 2011-03-05
    • 2016-01-09
    • 1970-01-01
    • 2017-05-29
    • 2016-05-31
    相关资源
    最近更新 更多