检查传递的参数在Python中是否有效的最佳方法是什么?

时间:2015-05-29 13:49:10

标签: python exception types parameters

我过去一年在Java工作,在那里我使用assert来确保传递给方法的参数满足某些先决条件。我想在Python中做同样的事情,但我读到here,使用异常比断言更好。

这就是我目前的情况:

if type(x) == List:
    x = np.array(x)
else:
    err = ("object passed for x is not a numpy.ndarray or a list")
    assert type(x) is np.ndarray, err
err = ("object passed for n is not an integer")
assert type(n) is IntType, err
err = ("the size of the object passed for x does not equal "
       "n squared")
assert x.size is n**2, err

是否有更优雅和/或Pythonic的方式来接近这个?我应该编写自己的异常类来在无效参数传递时加注吗?

4 个答案:

答案 0 :(得分:2)

不要限制自己

你有时会惊讶于许多函数,类等产生有用的输出,输入的类型多于原作者的意图,只要它与orignal类型相似。不要限制以后但不可预见的代码使用。这称为EAFP-Apporach

因此,只有在您知道代码会产生无意义结果的地方进行测试。

断言并不总是

当您停用断言(assert)时,python -O也不会做任何事情。

答案 1 :(得分:1)

首先,您应该使用例如检查对象的类型。 if isinstance(x, list),未使用type(x)。这处理例如继承更好(见Differences between isinstance() and type() in python)。

其次,如果x是列表实例,真的重要吗?一个元组会好吗?一些自定义列表子类?任何Sequence object?任何可以成为np.array的东西? Python使用强大但动态的"duck typing";具体类型不如具有正确行为那么重要。

一种选择是:

from collections import Sequence

def some_func(x, n):
    if not isinstance(x, (Sequence, np.ndarray)):
        raise TypeError('x must be a sequence or numpy array')
    x = np.ndarray(x)
    if x.size != n ** 2:  # possible TypeError if n**2 doesn't make sense
        raise ValueError('x must be {} long'.format(n ** 2))
    ...

这会引发TypeErrorxn的错误类型参数)或ValueErrorx是正确的类型,但错误大小),这比使AssertionError 发生更容易有效处理。

答案 2 :(得分:0)

在Python中,检查参数非常昂贵。通常的方法是确保错误类型的参数最终会破坏代码,并希望异常将为开发人员提供足够的线索以确定错误。

有些人更进一步,编写单元测试以确保代码以预期方式中断。

请记住,Python不是Java。在Java中,开发人员受到恐惧的驱使(某些类型可能是错误的,或者有人可能看到/使用他们不应该做的事情)。 Python并不支持大多数这些概念,因为我们觉得它们浪费了小型项目的时间,只有傻瓜才能在大型项目中花费时间,因为他们可以通过一堆小项目实现相同(和更多)。 / p>

这就是为什么我们很少检查参数类型。从积极的方面来说,如果这些类型只是表现的话,这可以让你传递更多的功能/方法。

答案 3 :(得分:0)

Python围绕着

的想法而构建
  

更容易请求宽恕而不是许可

(EAFP)

所以你应该采用Foo.bar 方法,而不是检查类型。

https://docs.python.org/2/glossary.html

我知道来自静态类型语言很奇怪,经过多年的C / C ++后,对我来说也是如此:)

可能类似以下内容。很难从这个numpy数组中猜出你真正想要的是什么。 IMO try catch应该围绕你应用于数组的操作,而不是它的初始化。

private void myMethod() {
    new Thread() {
        @Override
        public void run() {
            int i = 0;
            doWorkOnUI(String.valueOf(i));
            pause(2000);
            doWorkOnUI(String.valueOf(i++));
        }
    }.start();
}

private void pause(int pauseTime) {
    try {
        Thread.sleep(pauseTime);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private void doWorkOnUI(final String string) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            display1.setText(string);
        }
    });
}