提升尝试和断言之间的区别

时间:2016-10-21 18:07:38

标签: python assert raise

我已经学习了一段时间的Python而且raise函数和assert是(我意识到他们都崩溃了应用程序,不像尝试 - 除外)真的很相似,我可以&# 39;看到您使用raiseassert而不是try的情况。

那么,Raise,Try和Assert之间有什么区别?

10 个答案:

答案 0 :(得分:25)

断言:

当您想要"停止&#34>时使用基于某种条件的脚本并返回一些东西来帮助调试更快:

list_ = ["a","b","x"]
assert "x" in list_, "x is not in the list"
print("passed") 
#>> prints passed

list_ = ["a","b","c"]
assert "x" in list_, "x is not in the list"
print("passed")
#>> 
Traceback (most recent call last):
  File "python", line 2, in <module>
AssertionError: x is not in the list

抬起:

对此有用的两个原因:

1 /与try和except块一起使用。提出您选择的错误,可以像下面一样自定义,如果您passcontiune脚本,则不会停止脚本;或者可以是预定义的错误raise ValueError()

class Custom_error(BaseException):
    pass

try:
    print("hello")
    raise Custom_error
    print("world")
except Custom_error:
    print("found it not stopping now")

print("im outside")

>> hello
>> found it not stopping now
>> im outside

注意到它没有停止?我们可以使用except块中的exit(1)来停止它。

2 / Raise也可用于重新加载当前错误以将其传递到堆栈以查看是否有其他东西可以处理它。

except SomeError, e:
     if not can_handle(e):
          raise
     someone_take_care_of_it(e)

尝试/除了块:

完全符合您的想法,尝试一些事情,如果出现错误,您可以抓住它并按照您喜欢的方式处理它。没有例子,因为上面有一个。

答案 1 :(得分:22)

assert cond, "text"

扩展为类似

if cond == False:
  raise AssertionError("text")

使用assert因为它更具可读性。

答案 2 :(得分:17)

raise - 提出异常。

assert - 如果某个特定条件(或者不是真),则引发异常

try - 执行一些可能引发异常的代码,如果是,请抓住它。

答案 3 :(得分:9)

try/except块可让您捕获和管理异常。 raiseassert和大量错误(例如尝试索引空列表)可能会触发异常。检测到错误情况时,通常会使用raiseassert类似,但仅在满足条件时才会引发异常。

raiseassert有不同的理念。您检测到的代码中存在许多“正常”错误并引发错误。也许网站不存在或参数值超出范围。

断言通常保留为“我发誓这不可能发生”的问题,无论如何都会发生。它更像是运行时调试而不是正常运行时错误检测。如果您使用-O标志或从.pyo文件而不是.pyc文件运行,则可以禁用断言,因此它们不应成为常规错误检测的一部分。

如果生产质量代码引发异常,那么弄清楚你做错了什么。如果它提出AssertionError,你就会遇到更大的问题。

答案 4 :(得分:2)

assertraise AssertionError之间没有区别,它们将编译为完全相同的字节码:

import dis

def foo1(param):
    assert param, "fail"

def foo2(param):
    if not param:
        raise AssertionError("fail")

print(dis.dis(foo1))
print(dis.dis(foo2))
  

输出:

 4           0 LOAD_FAST                0 (param)
             2 POP_JUMP_IF_TRUE        12
             4 LOAD_GLOBAL              0 (AssertionError)
             6 LOAD_CONST               1 ('fail')
             8 CALL_FUNCTION            1
            10 RAISE_VARARGS            1
       >>   12 LOAD_CONST               0 (None)
            14 RETURN_VALUE
None
 7           0 LOAD_FAST                0 (param)
             2 POP_JUMP_IF_TRUE        12

 8           4 LOAD_GLOBAL              0 (AssertionError)
             6 LOAD_CONST               1 ('fail')
             8 CALL_FUNCTION            1
            10 RAISE_VARARGS            1
       >>   12 LOAD_CONST               0 (None)
            14 RETURN_VALUE
None

答案 5 :(得分:1)

异常是Python(和其他一些语言)用来处理执行代码时出现的错误的原因。 raise ExceptionName表示代码中存在错误,并通过引发与该问题相关的异常来指定它是什么类型的问题。 assert expression评估expression并在错误时引发异常。

try用于执行可能引发您期望的异常的代码。你可以“赶上”#34;而不是停止计划。异常并在您的代码中处理它。

示例:假设您有字典和列表。你希望从字典中的列表中查找内容,直到找到字典中没有的内容:

try:
    for item in my_list:
        print(my_dictionary[item])
except KeyError as e: #KeyError is the Exception raised when a key is not in a dictionary
    print('There is no {} in the dictionary'.format(e.args[0]))

答案 6 :(得分:1)

断言通常用于测试代码以确保某些工作正常:

def test_bool():
    assert True != False

尝试的时候,提高和除了化妆异常处理,这是python处理和传播错误的首选方法。

如果出现问题,大多数库和python内置函数都会引发一种或另一种类型的异常。通常在您自己的代码中,您还需要在检测到出错时引发异常。让我们举个例子说你正在编写一个电子邮件地址验证器,如果地址没有包含@符号,你想提出异常。你可能有类似的东西(这是玩具代码,实际上并不是这样验证电子邮件):

def validate_email(address):
    if not "@" in address:
        raise ValueError("Email Addresses must contain @ sign")

然后在代码中的其他地方你可以调用validate_email函数,如果失败则会抛出异常。

try:
    validate_email("Mynameisjoe.com")
except ValueError as ex:
    print("We can do some special invalid input handling here, Like ask the user to retry the input")
finally:
    close_my_connection()
    print("Finally always runs whether we succeed or not. Good for clean up like shutting things down.")

要知道的重要一点是,当引发异常时,它会在调用堆栈中向上传递,直到找到一个处理程序。如果它从未找到处理程序,那么它将使程序崩溃,异常和堆栈跟踪。

你不想做的一件事是:

if __name__ == '__main__':
    try:
        print(1/0)
    except Exception as ex:
        pass

现在你无法知道为什么你的应用程序爆炸了。

你经常会看到一件好事就是:

import logging
if __name__ == '__main__':
    try:
        print(1/0)
    except Exception as ex:
        logging.exception(ex)
        raise

在这种情况下加注,因为它没有参数重新引发相同的错误。通常在Web代码中,您会看到类似的东西,不会重新引发异常,因为它会向客户端发送500错误,然后继续下一个请求,因此在这种情况下,您不希望程序端。

答案 7 :(得分:1)

断言

  • 只能用于调试目的
  • 尽管与引发/异常相似,但它们有不同的用途,因为它们对于指出无法从中恢复程序错误的情况很有用
  • 断言总是会引发AssertionError异常,这是它们的工作方式:

语法assert_stmt ::= "assert" expression1 ["," expression2]

在执行时会翻译为

if __debug__:
  if not expression1:
    raise AssertionError(expression2)
  • __debug__是一个内置标志,通常为true,但是如果触发了优化,则它将为false,因此断言将是无效代码=>在启动Python时使用-O和-OO标志禁用(或CPython中的PYTHONOPTIMIZE env变量),因此,请勿依赖于它们的代码逻辑。
  • 由于先前的观点,请勿使用断言进行数据验证
  • 断言的一个好用例=>如果程序的某些意外状态应使其在所有情况下都停止运行,则使程序“爆炸” =>因此,在这种情况下,如果被捕获的异常会使程序完全退出。
  • 如果您的程序没有错误,那么断言将/永远不会触发,它们将作为程序的运行状况检查
  • 在断言中始终使用数据结构(例如元组)作为expression1时要小心,对于非空值,断言始终为True =>断言将始终被触发,从而破坏程序-例如:assert (<some_test>, 'warn string') = >注意元组构造(错误!)

检查:Catching bogus Python asserts on CI by Dan Bader

引发/例外

  • 他们的目的是处理程序逻辑处于异常状态但您知道从该状态恢复哪种逻辑的情况
  • 引发异常时,可以使异常的类型适合于错误(更好地控制语义值),并在以后捕获它=>,从而可以创建多个异常类型,这些异常类型应该从中恢复,并且处理他们
  • 它们是一种用于处理运行时错误的已知/预期情况的机制
  • 在使用if语句并在每个方案中引发验证异常时,可用于数据验证

尝试

  • 仅仅是编码异常处理的语法元素

顺便说一句,我强烈推荐Dan Bader的这本书"Python Tricks: The Book"(来自realpython.com

答案 8 :(得分:0)

另一个answers很好地解释了这些差异,但是许多人都没有提到使用-O优化器标志时assert语句将被忽略。

一个获得与assert相似的简洁语法的选项,使-O在使用时仍使异常生效,并且能够引发特定异常类型的好处是定义了这样的实用函数:

def raiseif(cond, msg="", exc=AssertionError):
    if cond:
        raise exc(msg)

raiseif(x != y, "x should equal y")

该逻辑与assert相反,但是您可以根据需要轻松更改。

答案 9 :(得分:0)

  • raise用于引发异常;
  • assert用于在给定条件为False的情况下引发异常。