Python Raise Try 和 Assert 之间的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40182944/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 23:14:11  来源:igfitidea点击:

Difference between Raise Try and Assert

pythonassertraise

提问by Defneit

I have been learning Python for a while and the raisefunction and assertare (what I realised is that both of them crash the app, unlike try - except) really similar and I can't see a situation where you would use raiseor assertover try.

我已经学习 Python 一段时间了,它的raise函数和assert(我意识到它们都使应用程序崩溃,不像 try - except)非常相似,我看不出你会使用raiseassertover 的情况try

So, what is the difference between Raise, Try and Assert?

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

采纳答案by MooingRawr

Assert:

断言:

Used when you want to "stop" the script based on a certain condition and return something to help debug faster:

当您想根据特定条件“停止”脚本并返回一些内容以帮助更快地调试时使用:

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


Raise:

增加:

Two reasons where this is useful:

这很有用的两个原因:

1/ To be used with try and except blocks. Raise an error of your choosing, could be custom like below and doesn't stop the script if you passor contiunethe script; or can be predefined errors raise ValueError()

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

Noticed it didn't stop? We can stop it using just exit(1) in the except block.

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

2/ Raise can also be used to re-raise current error to pass it up the stack to see if something else can handle it.

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

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


Try/Except blocks:

尝试/除外块:

Does exactly what you think, tries something, if an error comes up you catch it and deal with it how ever you like. No example since there's one above.

完全按照你的想法去做,尝试一些东西,如果出现错误,你会发现它并以你喜欢的方式处理它。没有例子,因为上面有一个。

回答by Michal Krzyz

assert cond, "text"

is expanded to something like

扩展到类似的东西

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

use assert because it is more readable.

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

回答by John Gordon

raise- raise an exception.

raise- 引发异常。

assert- raise an exception ifa given condition is (or isn't) true.

assert-如果给定条件为(或不为)真,引发异常。

try- execute some code that mightraise an exception, and if so, catch it.

try- 执行一些可能引发异常的代码,如果是,则捕获它。

回答by tdelaney

try/exceptblocks let you catch and manage exceptions. Exceptions can be triggered by raise, assert, and a large number of errors such as trying to index an empty list. raiseis typically used when you have detected an error condition. assertis similar but the exception is only raised if a condition is met.

try/except块让你捕捉和管理异常。异常可以由raiseassert和大量错误触发,例如尝试索引空列表。raise通常在您检测到错误情况时使用。assert类似,但只有在满足条件时才会引发异常。

raiseand asserthave a different philosophy. There are many "normal" errors in code that you detect and raise errors on. Perhaps a web site doesn't exist or a parameter value is out of range.

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

Assertions are generally reserved for "I swear this cannot happen" issues that seem to happen anyway. Its more like runtime debugging than normal runtime error detection. Assertions can be disabled if you use the -Oflag or run from .pyofiles instead of .pycfiles, so they should not be part of regular error detection.

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

If production quality code raises an exception, then figure out what you did wrong. If it raises an AssertionError, you've got a bigger problem.

如果生产质量代码引发异常,请找出您做错了什么。如果它引发了AssertionError,则您遇到了更大的问题。

回答by Rui Carvalho

Assertions

断言

  • Should only be used for debugging purposes
  • Although similar to Raise/Exceptions they serve different purposes, because they are useful to point scenarios where program error cannot be recovered from
  • Assertions always raise AssertionError exceptions, here's how they work:
  • 应该只用于调试目的
  • 尽管与 Raise/Exceptions 类似,但它们有不同的用途,因为它们可用于指出无法从中恢复程序错误的场景
  • 断言总是引发 AssertionError 异常,它们的工作原理如下:

syntax: assert_stmt ::= "assert" expression1 ["," expression2]

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

at execution time it translates to:

在执行时它转换为

if __debug__:
  if not expression1:
    raise AssertionError(expression2)
  • __debug__is a built-in flag that is usually true, but if optimisations are triggered it will be false, thus assertions will be dead code => disabled with the -O and -OO flags when starting Python (or PYTHONOPTIMIZE env variable in CPython), so, don't rely on them for code logic.
  • Don't Use Asserts for Data Validation because of previous point
  • A good use case for assertions => make program "explode" if some unexpected state of the program should make it stop under all circumstances => thus, under circumstances where an exception if caught would make program exit altogether.
  • If you have a bug-free program, then assertions will/should never be triggered, they serve as health checks for the program
  • Careful when using a data structures (such as tuples) as the expression1 in assertions that always evaluate to True for non-empty values => the assertions will always be triggered, breaking down program - eg: assert (<some_test>, 'warn string')=> notice the tuple construct (wrong!)
  • __debug__是一个内置标志,通常为真,但如果优化被触发,它将为假,因此断言将是死代码 => 在启动 Python 时使用 -O 和 -OO 标志禁用(或 CPython 中的 PYTHONOPTIMIZE 环境变量),所以,不要依赖它们来进行代码逻辑。
  • 由于前一点,不要使用断言进行数据验证
  • 断言的一个很好的用例 => 使程序“爆炸”,如果程序的某些意外状态应该使其在所有情况下都停止 => 因此,在捕获异常将使程序完全退出的情况下。
  • 如果你有一个没有错误的程序,那么断言将/不应该被触发,它们作为程序的健康检查
  • 在使用数据结构(例如元组)作为对于非空值总是评估为 True 的断言中的 expression1 时要小心=> 断言将始终被触发,破坏程序 - 例如:assert (<some_test>, 'warn string')=> 注意元组构造(错误! )

Check: Catching bogus Python asserts on CI by Dan Bader

检查:Dan Bader 在 CI 上捕获虚假的 Python 断言

Raise/Exceptions

引发/异常

  • Their purpose is to handle scenarios where program logic is in an exceptional state but you know what logic to recover from that state
  • When you raise an exception, you can make the type of the exception appropriate to the error (better control over semantic value) and catch it later => so you can create multiple exception types that you know how to recover from, and handle them
  • They are a mechanism for handling known/expected scenarios of run-time errors
  • Useful for data validation when using if-statements and raising validation exceptions per scenario
  • 它们的目的是处理程序逻辑处于异常状态但您知道从该状态恢复什么逻辑的情况
  • 当您引发异常时,您可以使异常的类型适合错误(更好地控制语义值)并稍后捕获它 => 这样您就可以创建多个知道如何从中恢复并处理它们的异常类型
  • 它们是一种用于处理已知/预期的运行时错误场景的机制
  • 在使用 if 语句并在每个场景中引发验证异常时对数据验证很有用

Try

尝试

  • Is just a syntactic element of coding exceptions handling
  • 只是编码异常处理的语法元素

BTW, I highly recommend the book, "Python Tricks: The Book"by Dan Bader (from realpython.com)

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

回答by ruohola

When they are in place, there is no difference between assertand raise AssertionError, they will compile to the exact same bytecode:

当它们就位时,assert和之间没有区别raise 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))

Output:

 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

输出:

 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

But keep i mind that assertstataments will be disabled when running Python with the -Oor -OOflags, this is not the case with any raise statements.

但是请记住,assert使用-Oor-OO标志运行 Python 时,stataments 将被禁用,任何 raise 语句都不是这种情况。

回答by Michael Robellard

Assert is generally used by testing code to make sure that something worked:

Assert 通常用于测试代码以确保某些内容有效:

def test_bool():
    assert True != False

Where as try, raise and except makeup exception handling which is the preferred way in python to handle and propagate errors.

其中 try、raise 和 except 异常处理是 Python 中处理和传播错误的首选方式。

Most libraries and the python built-ins will raise and Exception of one type or another if something goes wrong. Often in you own code you will also want to raise an exception when you detect something going wrong. Let's say as an example you were writing an email address validator and you wanted to raise an exception if the address didn't contain an @ sign. you could have something like (This is toy code, don't actually validate emails like this):

如果出现问题,大多数库和 python 内置程序将引发一种或另一种类型的异常。通常在您自己的代码中,当您检测到出现问题时,您还希望引发异常。举个例子,假设您正在编写一个电子邮件地址验证器,并且您想在地址不包含 @ 符号时引发异常。你可以有类似的东西(这是玩具代码,实际上不要像这样验证电子邮件):

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

Then somewhere else in your code you can call the validate_email function and if it fails an exception will be thrown.

然后在您的代码中的其他地方,您可以调用 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.")

The important thing to know is that when an exception is raised it gets passed up the call stack until it finds a handler. If it never finds a handler then it will crash the program with the exception and the stack trace.

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

One thing you don't want to do is something like:

您不想做的一件事是:

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

Now you have no way of knowing why your application blew up.

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

One thing you will see often which is ok is something like:

你会经常看到的一件事是:

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

The raise in this case since it has no parameters re-raises the same error. Often in web code you will see something similar that does not re-raise the exception because it will send the 500 error to the client and then carry on with the next request, so in that case you don't want the program to end.

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

回答by Patrick Haugh

Exceptions are what Python (and some other languages) use to deal with errors that arise when executing code. raise ExceptionNameis saying that there is an error in the code, and specifies what kind of problem it is by raising the Exception associated with that problem. assert expressionevaluate expressionand raises an Exception if it is false.

异常是 Python(和其他一些语言)用来处理执行代码时出现的错误的东西。 raise ExceptionName是说代码中有错误,并通过引发与该问题相关的异常来指定它是什么类型的问题。 如果为假,则assert expression评估expression并引发异常。

tryis used to execute code that might raise an Exception that you're expecting. Instead of stopping the program, you can "catch" the exception and deal with it in your code.

try用于执行可能引发您期望的异常的代码。您可以“捕获”异常并在代码中处理它,而不是停止程序。

Example: Let's say that you have a dictionary and a list. You want to look things from the list in the dictionary until you reach one that isn't in the dictionary:

示例:假设您有一本字典和一个列表。您想从字典中的列表中查找内容,直到找到字典中没有的内容:

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]))

回答by totalhack

The other answersexplain the differences pretty well, but many fail to mention that assertstatements are ignored when the -O optimizer flag is used.

其他答案很好地解释了差异,但许多人没有提到assert使用 -O 优化器标志时会忽略语句。

One option to get similarly concise syntax to assert, still have the exceptions take effect when -O is in use, and get the benefits of being able to raise specific exception types is to define a utility function like this:

获得与 类似的简洁语法assert,在使用 -O 时仍然使异常生效,并获得能够引发特定异常类型的好处的一种选择是定义一个实用程序函数,如下所示:

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

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

The logic is inverted from assertbut you can easily change that if you want.

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