为什么我们需要 Python 中的 try/except 的 except 块?
Why do we need an except block for the try/except in Python?
我明白它的作用,但我不明白我们为什么要这样做?为什么我们要排除某些东西?
例如:
for i, value in enumerate(arr):
try:
result_dict[value] += 1
except KeyError:
result_dict[value] = 1
除了 KeyError 为什么我必须做?我不知道为什么会抛出 KeyError。为什么我不能做
result_dict[value] += 1
第一?
任何 try/catch 的 except 块中包含什么?我知道必须抛出错误,但在 except 块内必须执行什么条件?
抱歉,如果我的问题太愚蠢了。我是初学者。
原因如下。您不能添加 None 的内容。例如说 var1 = None
。我不能做类似 var = var + 1
的事情。那会引发错误。在您共享的示例中,代码将检查您是否可以将 1 添加到值的键。如果您不能这样做,您可以为该键分配一个值。
for i, value in enumerate(arr):
try:
#Try and add 1 to a dict key's value.
result_dict[value] += 1
except KeyError:
#Say we get an error we need to assign the dict key's value to 1.
result_dict[value] = 1
如果 result_dict[value]
不存在,A KeyError
将 crash/terminate 您的程序。通过使用 except
块,您可以告诉程序在出现 KeyError 时要做什么(这里,如果它不存在,则分配 result_dict[value] = 1
),然后程序继续。基本上,您是在避免崩溃。
假设您的 value
是 "banana"
。如果你没有 result_dict["banana"]
,你不能加 1 到无,即 None += 1
.
通过使用 except KeyError
,您可以在程序停止之前拦截错误,现在您已经为 result_dict
设置了键值对,而不是终止程序。
TLDR
try/except
块确保您的程序继续 运行ning 而不是突然结束。通过包含 except KeyError
,我们特别确保程序不会在出现 KeyError
时突然结束。如果 value
不是字典中的键,result_dict[value] += 1
将抛出错误,因为它试图访问不存在的键。 +=
使代码 运行 类似于:
result_dict[value] = result_dict[value] + 1
并且由于 value
不在 result_dict 中,这类似于说
result_dict[value] = None + 1
哪个不好。
非 TLDR 版本
当python发生错误时,程序通常会突然终止并退出。它不会 运行 发生异常的部分下方出现的任何代码。例如,采用以下代码。它从用户 a
和 b
那里获取 2 个数字,它会输出 a/b
a = int(input("Enter a value for a: "))
b = int(input("Enter a value for b: "))
print("a/b is:", a/b)
如果用户提供有效输入(比如 a=4, b=2
),程序将顺利进行。但是,如果用户要给出 a = "c"
,则会发生以下情况
Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'c'
然后程序戛然而止。让程序像这样结束是完全正确的,但你很少希望程序突然结束。假设用户有 1000 个输入,最后一个输入搞砸了。然后用户将不得不重新启动程序并再次重新输入所有 1000 个输入,因为程序突然结束。
所以现在我们引入一个try/except
块。我们知道将非数字字符转换为整数会抛出一个 ValueError
,如错误所示,因此我们将相应地处理它们
while True:
try:
a = int(input("Enter a value for a: "))
break
except:
print("An error has occurred. Please input a again")
while True:
try:
b = int(input("Enter a value for b: "))
break
except:
print("An error has occurred. Please input b again")
print("a/b is:", a/b)
所以现在,我们从用户那里获取输入,尝试 将其转换为整数并将该值放入 a
。如果成功,它将顺利进行到下一行(break
)并退出循环。如果失败,则会出现 exception,然后进入 except
块,打印有用的错误消息,然后再次 运行 循环(直到用户输入有效输入)。现在程序不会在失败时突然终止。它向用户提供适当的反馈,并让用户再次尝试输入。
这是一个通用的异常块,您可以在其中捕获任何异常。
但是现在假设可能会发生多种可能的错误。取以下代码:
a = input()
b = input()
print(int(a)/int(b))
print("I am done")
现在可能会出现一些错误。其中之一就是上面提到的ValueError
,其中给定的输入无法转换为整数。另一个错误是 ZeroDivisionError
,其中 b=0
。 Python 不喜欢除以零,因此会抛出异常并立即终止程序。
现在,您想要为每种类型的程序打印一条特殊消息。你如何做到这一点是通过 捕获特定的异常
a = input("Enter a value for a: ")
b = input("Enter a value for b: ")
try:
print(int(a)/int(b))
except ValueError:
print("We cannot convert a non-numeric character to an integer")
except ZeroDivisionError:
print("We cannot divide by 0")
except:
print("Some unexpected error has occurred")
print("I am done")
如果python无法将输入转换为整数,则会进入代码的ValueError
块,打印"We cannot convert a non-numeric character to an integer"
如果python试图除以0,那么它将进入ZeroDivisionError
块并打印"We cannot divide by 0"
如果发生任何其他类型的错误,它将在最后的 except 块中结束并打印 "Some unexpected error has occurred"
并且在处理异常后,打印"I am done"
请注意,如果最后的 except
块没有捕获任何其他异常,那么程序将不会很好地终止,因为异常未被处理,并且它不会打印最终语句。
现在,如何意识到可能发生的错误?这要靠实践,一旦你熟悉了错误,你就可以相应地处理它们。或者,故意让您的程序抛出异常,并读取堆栈跟踪以了解发生了何种异常。然后相应地处理它们。您不必以不同方式处理每个特定错误,您可以用相同的方式处理所有错误。
您可以在此处阅读更多内容:Python's documentation for errors and exceptions
让我们从一个例子开始
我们的公寓楼里有租户,他们可以预订停车位。有些租户没有车,也没有停车位,但只有租户可以预订停车位。我们在字典中跟踪停车位:
parking_spots = { "alice": 1, "bob": 2, "chris": 0 }
克里斯没有斑点,因为他步行上班。
如果 Eve 试图保留位置会怎样?
parking_spots["eve"]
该代码询问“已经保留了多少个位置?”然而,这个回答的另一个问题是夏娃是否是大楼的租户。 Python 通过让 parking_spots["eve"]
抛出一个不同于任何其他值的 KeyError
来表示这一点。如果 python 没有这样做并且默认情况下 returned 0,那么 parking_spots["eve"]
和 parking_spots["chris"]
看起来是一样的。
但是等等,我知道这本特定的词典不是那样使用的
太棒了,这很常见。事实上,这很常见,有多种方法可以做到这一点。
而不是
result_dict = {}
for i, value in enumerate(arr):
try:
result_dict[value] += 1
except KeyError:
result_dict[value] = 1
你可以使用
result_dict = {}
result_dict.setdefault(0)
result_dict += 1
或者您可以使用 defaultdict
.
from collections import defaultdict
result_dict = defaultdict(int)
result_dict += 1
一些CS理论
我们可以在这里讨论两个理论概念:
- 作为控制流机制的异常
- 字典api
控制流异常
try/catch
是控制流的样式。它只是一种更好的方式来考虑某些情况下的代码。只要您可以使用 if/else
,几乎从不 需要 ,但很多时候这是思考代码的最佳方式。
根据您与谁交谈,异常处理可能是一个有争议的功能:
C++ - Arguments for Exceptions over Return Codes
在我看来,如果您从头开始设计系统,异常很少是真正正确的答案。通常,我更喜欢使用 Option
(或更普遍的求和类型)。
但是,在很多情况下,它们是给定起始限制的最佳答案。
词典API
Python 在键不存在时抛出异常是一种设计选择,而不是 API 可以编写的唯一方式。相反,它可以简单地 return None
。许多语言都采用后一种方法,因为他们认为它更安全——尤其是当您使用 Rust、Haskell、Elm 等现代类型语言时
进一步阅读
我还鼓励您阅读 ,因为它涵盖了一些可能具有指导意义的异常处理细节的其他细节。
我明白它的作用,但我不明白我们为什么要这样做?为什么我们要排除某些东西?
例如:
for i, value in enumerate(arr):
try:
result_dict[value] += 1
except KeyError:
result_dict[value] = 1
除了 KeyError 为什么我必须做?我不知道为什么会抛出 KeyError。为什么我不能做
result_dict[value] += 1
第一?
任何 try/catch 的 except 块中包含什么?我知道必须抛出错误,但在 except 块内必须执行什么条件?
抱歉,如果我的问题太愚蠢了。我是初学者。
原因如下。您不能添加 None 的内容。例如说 var1 = None
。我不能做类似 var = var + 1
的事情。那会引发错误。在您共享的示例中,代码将检查您是否可以将 1 添加到值的键。如果您不能这样做,您可以为该键分配一个值。
for i, value in enumerate(arr):
try:
#Try and add 1 to a dict key's value.
result_dict[value] += 1
except KeyError:
#Say we get an error we need to assign the dict key's value to 1.
result_dict[value] = 1
result_dict[value]
不存在,A KeyError
将 crash/terminate 您的程序。通过使用 except
块,您可以告诉程序在出现 KeyError 时要做什么(这里,如果它不存在,则分配 result_dict[value] = 1
),然后程序继续。基本上,您是在避免崩溃。
假设您的 value
是 "banana"
。如果你没有 result_dict["banana"]
,你不能加 1 到无,即 None += 1
.
通过使用 except KeyError
,您可以在程序停止之前拦截错误,现在您已经为 result_dict
设置了键值对,而不是终止程序。
TLDR
try/except
块确保您的程序继续 运行ning 而不是突然结束。通过包含 except KeyError
,我们特别确保程序不会在出现 KeyError
时突然结束。如果 value
不是字典中的键,result_dict[value] += 1
将抛出错误,因为它试图访问不存在的键。 +=
使代码 运行 类似于:
result_dict[value] = result_dict[value] + 1
并且由于 value
不在 result_dict 中,这类似于说
result_dict[value] = None + 1
哪个不好。
非 TLDR 版本
当python发生错误时,程序通常会突然终止并退出。它不会 运行 发生异常的部分下方出现的任何代码。例如,采用以下代码。它从用户 a
和 b
那里获取 2 个数字,它会输出 a/b
a = int(input("Enter a value for a: "))
b = int(input("Enter a value for b: "))
print("a/b is:", a/b)
如果用户提供有效输入(比如 a=4, b=2
),程序将顺利进行。但是,如果用户要给出 a = "c"
,则会发生以下情况
Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'c'
然后程序戛然而止。让程序像这样结束是完全正确的,但你很少希望程序突然结束。假设用户有 1000 个输入,最后一个输入搞砸了。然后用户将不得不重新启动程序并再次重新输入所有 1000 个输入,因为程序突然结束。
所以现在我们引入一个try/except
块。我们知道将非数字字符转换为整数会抛出一个 ValueError
,如错误所示,因此我们将相应地处理它们
while True:
try:
a = int(input("Enter a value for a: "))
break
except:
print("An error has occurred. Please input a again")
while True:
try:
b = int(input("Enter a value for b: "))
break
except:
print("An error has occurred. Please input b again")
print("a/b is:", a/b)
所以现在,我们从用户那里获取输入,尝试 将其转换为整数并将该值放入 a
。如果成功,它将顺利进行到下一行(break
)并退出循环。如果失败,则会出现 exception,然后进入 except
块,打印有用的错误消息,然后再次 运行 循环(直到用户输入有效输入)。现在程序不会在失败时突然终止。它向用户提供适当的反馈,并让用户再次尝试输入。
这是一个通用的异常块,您可以在其中捕获任何异常。
但是现在假设可能会发生多种可能的错误。取以下代码:
a = input()
b = input()
print(int(a)/int(b))
print("I am done")
现在可能会出现一些错误。其中之一就是上面提到的ValueError
,其中给定的输入无法转换为整数。另一个错误是 ZeroDivisionError
,其中 b=0
。 Python 不喜欢除以零,因此会抛出异常并立即终止程序。
现在,您想要为每种类型的程序打印一条特殊消息。你如何做到这一点是通过 捕获特定的异常
a = input("Enter a value for a: ")
b = input("Enter a value for b: ")
try:
print(int(a)/int(b))
except ValueError:
print("We cannot convert a non-numeric character to an integer")
except ZeroDivisionError:
print("We cannot divide by 0")
except:
print("Some unexpected error has occurred")
print("I am done")
如果python无法将输入转换为整数,则会进入代码的ValueError
块,打印"We cannot convert a non-numeric character to an integer"
如果python试图除以0,那么它将进入ZeroDivisionError
块并打印"We cannot divide by 0"
如果发生任何其他类型的错误,它将在最后的 except 块中结束并打印 "Some unexpected error has occurred"
并且在处理异常后,打印"I am done"
请注意,如果最后的 except
块没有捕获任何其他异常,那么程序将不会很好地终止,因为异常未被处理,并且它不会打印最终语句。
现在,如何意识到可能发生的错误?这要靠实践,一旦你熟悉了错误,你就可以相应地处理它们。或者,故意让您的程序抛出异常,并读取堆栈跟踪以了解发生了何种异常。然后相应地处理它们。您不必以不同方式处理每个特定错误,您可以用相同的方式处理所有错误。
您可以在此处阅读更多内容:Python's documentation for errors and exceptions
让我们从一个例子开始
我们的公寓楼里有租户,他们可以预订停车位。有些租户没有车,也没有停车位,但只有租户可以预订停车位。我们在字典中跟踪停车位:
parking_spots = { "alice": 1, "bob": 2, "chris": 0 }
克里斯没有斑点,因为他步行上班。
如果 Eve 试图保留位置会怎样?
parking_spots["eve"]
该代码询问“已经保留了多少个位置?”然而,这个回答的另一个问题是夏娃是否是大楼的租户。 Python 通过让 parking_spots["eve"]
抛出一个不同于任何其他值的 KeyError
来表示这一点。如果 python 没有这样做并且默认情况下 returned 0,那么 parking_spots["eve"]
和 parking_spots["chris"]
看起来是一样的。
但是等等,我知道这本特定的词典不是那样使用的
太棒了,这很常见。事实上,这很常见,有多种方法可以做到这一点。
而不是
result_dict = {}
for i, value in enumerate(arr):
try:
result_dict[value] += 1
except KeyError:
result_dict[value] = 1
你可以使用
result_dict = {}
result_dict.setdefault(0)
result_dict += 1
或者您可以使用 defaultdict
.
from collections import defaultdict
result_dict = defaultdict(int)
result_dict += 1
一些CS理论
我们可以在这里讨论两个理论概念:
- 作为控制流机制的异常
- 字典api
控制流异常
try/catch
是控制流的样式。它只是一种更好的方式来考虑某些情况下的代码。只要您可以使用 if/else
,几乎从不 需要 ,但很多时候这是思考代码的最佳方式。
根据您与谁交谈,异常处理可能是一个有争议的功能: C++ - Arguments for Exceptions over Return Codes
在我看来,如果您从头开始设计系统,异常很少是真正正确的答案。通常,我更喜欢使用 Option
(或更普遍的求和类型)。
但是,在很多情况下,它们是给定起始限制的最佳答案。
词典API
Python 在键不存在时抛出异常是一种设计选择,而不是 API 可以编写的唯一方式。相反,它可以简单地 return None
。许多语言都采用后一种方法,因为他们认为它更安全——尤其是当您使用 Rust、Haskell、Elm 等现代类型语言时
进一步阅读
我还鼓励您阅读