简体   繁体   English

Python异常处理 - 如何做到pythonic?

[英]Python exception handling - How to do it pythonic?

I am still learning the Python programmimg language. 我还在学习Python programmimg语言。 I asked myself in terms of code exceptions, when it is neccessary to handle such situations in a pythonic way. 我在代码异常方面问自己,当需要以pythonic方式处理这种情况时。 I read a few times "you should never pass an error silently". 我读了几遍“你永远不应该默默地传递错误”。

For example a little function: 例如一个小功能:

def square(list_with_items):
    return [i**2 for i in list_with_items]

Is it neccessary to write an error-handler, if somebody passes a tuple as parameter? 如果有人将元组作为参数传递,是否需要编写错误处理程序? Or it is more senseful to do it, when I have to check the validation of user-input? 或者,当我必须检查用户输入的验证时,它更有意义吗?

In the specific case of checking types, the "Pythonic" thing to do is not to check them. 在检查类型的特定情况下,“Pythonic”要做的就是不检查它们。 Unless there is a good reason, you should assume that the caller is passing in a sensible type (note: "sensible type" might be different from "the type you expect"), and do your best to return something sensible as well. 除非有充分的理由,否则你应该假设呼叫者传递的是合理类型(注意:“明智的类型”可能与“你期望的类型”不同),并尽力返回合理的东西。 If the caller passes in a type that isn't sensible, it's perfectly acceptable to let them deal with the consequences. 如果呼叫者传递的是一种不合理的类型,那么让他们处理后果是完全可以接受的。

For example, someone might sensibly pass an iterator of Decimal numbers into your square function: 例如,有人可能明智地将Decimal数字的迭代器传递给square函数:

>>> from decimal import Decimal
>>> square(Decimal(line.strip()) for line in open("numbers.txt")
[Decimal("4.0"), Decimal("9.0"), ...]

And everything would work! 一切都会奏效! But explicitly checking the types would make that use case more difficult. 但明确检查类型会使该用例更加困难。

And then, for example, if someone passes in something that isn't sensible, they can deal with the error: 然后,例如,如果有人传递了一些不合理的东西,他们就可以处理错误:

>>> square(42)
…
TypeError: 'int' object isn't iterable

This error message will also (in a script) contain all the file names and line numbers necessary to debug the issue. 此错误消息还将(在脚本中)包含调试问题所需的所有文件名和行号。

On the other hand, it is sometimes useful to explicitly check the arguments, when the caller might make a mistake with surprising consequences. 另一方面,当调用者可能会出现令人惊讶的后果时,显式检查参数有时很有用。 For example, if you're writing a function which will exhibit very poor performance with a list because it expects a deque , then a check for if not isinstance(input, deque): raise TypeError("a deque must be used!") might be justified. 例如,如果你正在编写一个函数,它会在list表现出非常糟糕的性能,因为它需要deque ,那么检查if not isinstance(input, deque): raise TypeError("a deque must be used!")可能是有道理的。

The name for this "method for dealing with types" is called Duck Typing . 这种“处理类型的方法”的名称叫做Duck Typing

You could use an assertion: 你可以使用一个断言:

def square(list_with_items):
    assert(all([type(x) == int for x in list_with_items]))
    return [i**2 for i in list_with_items]

You could use two assertions: 你可以使用两个断言:

def square(list_with_items):
    assert(type(list_with_items) in (list, tuple))
    assert(all([type(x) == int for x in list_with_items]))
    return [i**2 for i in list_with_items]

You could use an assertion and a try/catch: 你可以使用断言和try / catch:

def square(list_with_items):
    assert(type(list_with_items) in (list, tuple))
    try:
        return [i**2 for i in list_with_items]
    except TypeError:
        raise Exception("Each element of the argument must be a number.")

It depends. 这取决于。 In that specific example, if you are going to use the return value of "square" in "read-only" manner, you shouldn't have a "real bug" passing a tuple as argument. 在该具体示例中,如果您要以“只读”的方式使用“square”的返回值,则不应该有一个“真正的错误”将元组作为参数传递。 That's because even if the tuple is immutable, your function will return a new tuple with the square of the elements of the first one. 这是因为即使元组是不可变的,你的函数也会返回一个带有第一个元素的平方的新元组。

Anyhow, I suggest you to use a simple if-else statement, to be more precise and to avoid issues (ie: if you are going to call this function in a different way in future): 无论如何,我建议你使用一个简单的if-else语句来更精确地避免问题(例如:如果你将来以不同的方式调用这个函数):

def square(list_with_items):
    if isinstance(list_with_items, list): # True if list_with_items is a list - False otherwise
        return [i**2 for i in list_with_items]
    else:
        return 'Error: type(list_with_items) must be a list!'

EDIT: If you prefer (and if you are going to catch the exception with try-except statement), you could use "raise Exception" in the else-statement: 编辑:如果您愿意(如果您要使用try-except语句捕获异常),则可以在else语句中使用“raise Exception”:

else:
    raise Exception('Error: type(list_with_items) must be a list!')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM