Start Catching
예외에 익숙하지 않은 경우를 대비해 일반적인 정의부터 시작하겠습니다...
Exception: (계산) 정상적인 처리 중에 발생하는 중단으로, 일반적으로 오류 조건으로 인해 발생합니다. 프로세스의 다른 부분으로 인해 발생할 수 있습니다.
간단한 예를 살펴보겠습니다.
def initiate_security_protocol(code): if code == 1: print("Returning onboard companion to home location...") if code == 712: print("Dematerializing to preset location...") code = int(input("Enter security protocol code: ")) initiate_security_protocol(code)
>>> Enter security protocol code: 712 Dematerializing to preset location... >>> Enter security protocol code: seven one two Traceback (most recent call last): File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/security_protocols.py", line 7, in <module> code = int(input("Enter security protocol code: ")) ValueError: invalid literal for int() with base 10: 'seven one two'</module>
분명히 이것은 실수입니다. 우리는 사용자가 이상한 것을 입력했기 때문에 프로그램이 갑자기 중단되는 것을 원하지 않습니다. 농담으로 말하자면...
QA 엔지니어가 술집에 들어갑니다. 그는 맥주를 주문했다. 그는 맥주 다섯 잔을 주문했다. 그는 -1 맥주를 주문했습니다. 그는 도마뱀을 주문했습니다.
이상한 입력을 방지하고 싶습니다. 이 경우 중요한 실패 지점은 int()
함수뿐입니다. 정수로 변환할 수 있는 인수가 필요하며, 인수를 얻지 못하면 ValueError
예외가 발생합니다. 이를 적절하게 처리하기 위해 실패할 수 있는 코드를 try...out
블록에 래핑합니다. int()
函数。它期望接收可以转换为整数的参数,如果它没有得到它,则会抛出ValueError
异常。为了正确处理这个问题,我们将可能失败的代码包装在一个try...except
块中。
try: code = int(input("Enter security protocol code: ")) except ValueError: code = 0 initiate_security_protocol(code)
当我们再次测试我们的代码时,我们不会遇到这种失败错误。如果我们无法从用户那里获得我们需要的信息,我们将只需要设置code=0
。当然,我们可以重写我们的initiate_security_protocol()
函数来处理0
不同的代码,但是我不会在这里展示,只是为了节省时间。
注意:无论出于何种原因,作为一名多语言程序员,我经常忘记在 Python 中使用except
,而用大多数其他语言所使用的catch
语句。我已经在这篇文章中打错了三遍(然后立即修复它)。这只是一个记忆点。值得庆幸的是,Python没有catch
的关键字,因此语法错误会很突出。如果你会多种语言,当你感到困惑时,请不要惊慌。python里是except
,不是catch
。
阅读Traceback
在我们深入探讨该try...except
语句的一些更深层次的细节之前,让我们再次回顾一下该错误语句。毕竟,如果我们不讨论错误消息,那么一篇关于错误处理的文章有什么用呢?在 Python 中,我们称之为Traceback,因为它从涉及的第一行代码到最后一行跟踪错误的起源。在许多其他语言中,这将被称为堆栈跟踪( stack trace)。
Traceback (most recent call last): File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/security_protocols.py", line 7, in <module> code = int(input("Enter security protocol code: ")) ValueError: invalid literal for int() with base 10: 'seven one two'</module>
我有从下到上阅读这些信息的习惯,因为它可以帮助我首先获得最重要的信息。如果你查看最后一行,你会看到ValueError
,这是已引发的特定异常。确切的细节如下;在这种情况下,无法使用 . 将字符串'seven one two'
用int()
转换为整数。我们还了解到它正在尝试转换为以10 为底的整数,这在其他场景中可能是有用的信息。想象一下,例如,如果那行改成...
ValueError: invalid literal for int() with base 10: '5bff'
如果我们忘记指定以 16 为基数进行int('5bff', 16)
转化,而不是默认值(以 10 为基数),这是完全可能的。简而言之,你应该始终彻底阅读并理解错误消息的最后一行!有太多次我看了一半的帖子,花了半个小时追错了bug,才发现我忘记了一个参数或使用了错误的函数。
错误消息上方是错误来自 ( code = int(input("Enter security protocol code: "))
) 的代码行。上面是文件的绝对路径 ( security_protocols.py
) 和行号7
。该语句in <module></module>
意味着代码在任何函数之外。在这个例子中,回调只有一步,所以让我们看一些稍微复杂一点的东西。我已经更改并扩展了之前的代码。
Traceback (most recent call last): File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 6, in <module> decode_message("Bad Wolf") File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 4, in decode_message initiate_security_protocol(message) File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/security_protocols.py", line 2, in initiate_security_protocol code = int(code) ValueError: invalid literal for int() with base 10: 'Bad Wolf'</module>
我们遇到了与以前类似的错误 - 我们正在尝试将字符串转换为整数,但它不起作用。倒数第二行向我们展示了失败的代码;果然,这儿提到了int()
这一点。根据上面的行,这个有问题的代码位于security_protocols.py
文件的第2 行initiate_security_protocol()
函数内部!我们就可以马上找到那儿,并将其包装在一个try...except
datafile_index = { # Omitted for brevity. # Just assume there's a lot of data in here. } def get_datafile_id(subject): id = datafile_index[subject] print(f"See datafile {id}.") get_datafile_id("Clara Oswald") get_datafile_id("Ashildir")
코드를 다시 테스트하면 이 실패 오류가 발생하지 않습니다. 사용자로부터 필요한 정보를 얻을 수 없으면 code=0
으로 설정합니다. 물론 0
개의 다른 코드를 처리하기 위해 initiate_security_protocol()
함수를 다시 작성할 수도 있지만 여기서는 시간을 절약하기 위해 표시하지 않겠습니다.
🎜참고: 🎜어떤 이유로든 다중 언어 프로그래머로서 저는 종종 Python에서 out
을 사용하는 것을 잊어버리고 대신 catch 대부분의 다른 언어에서 사용되는 문입니다. 이 게시물에 세 번이나 잘못 입력했습니다(그런 다음 즉시 수정했습니다). 이것은 단지 추억의 지점일 뿐입니다. 다행히 Python은 키워드를<em>잡지</em><code>잡지
않으므로 구문 오류가 눈에 띕니다. 다국어 사용자라면 귀하가 혼란스러워도 당황하지 마세요. Python에서는 catch
가 아니라 excess
입니다. 🎜
이 시도...제외
를 시작하기 전에 Traceback을 읽어보세요🎜
> 명령문에 대한 더 자세한 내용을 살펴보기 전에 오류 명령문을 다시 검토해 보겠습니다. 결국, 오류 메시지를 논의하지 않는다면 오류 처리에 관한 기사가 무슨 소용이 있겠습니까? Python에서는 관련된 코드의 첫 줄부터 마지막 줄까지 오류의 원인을 추적하기 때문에 이를 🎜Traceback🎜이라고 부릅니다. 다른 많은 언어에서는 이를 스택 추적이라고 합니다. 🎜
See datafile 6035215751266852927. Traceback (most recent call last): File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 30, in <module> get_datafile_id("Ashildir") File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 26, in get_datafile_id id = datafile_index[subject] KeyError: 'Ashildir'</module>
저는 이 정보를 아래에서 위로 읽는 습관이 있습니다. 가장 중요한 정보를 먼저 얻는 데 도움이 되기 때문입니다. 마지막 줄을 보면 발생한 특정 예외인 ValueError
가 표시됩니다. 정확한 내용은 다음과 같습니다. 이 경우 int()
를 사용하여 문자열 'seven one two'
를 정수로 변환할 수 없습니다. 또한 다른 시나리오에서 유용한 정보가 될 수 있는 10진법 정수로 변환을 시도하고 있다는 것도 알게 됩니다. 예를 들어, 해당 줄이 다음과 같이 변경되었다고 상상해 보세요... 🎜
def get_datafile_id(subject): if subject in datafile_index: id = datafile_index[subject] print(f"See datafile {id}.") else: print(f"Datafile not found on {subject})
int('5bff', 16)에 대해 기본 16을 지정하는 것을 잊었다면 어떻게 될까요? code >기본값(기본 10) 대신 변환하는 것은 전적으로 가능합니다. 즉, 🎜항상 오류 메시지의 마지막 줄을 철저하게 읽고 이해해야 합니다! 🎜 게시물의 절반을 읽고 버그를 추적하는 데 30분을 소비했지만 매개 변수를 잊어버렸거나 잘못된 기능을 사용했다는 사실을 깨닫게 된 경우가 너무 많았습니다. 🎜<p data-id="p838747a-AIWJqVPB">오류 메시지 위에는 오류가 발생한 코드 줄이 있습니다( <code>code = int(input("보안 프로토콜 코드 입력: "))
). 위는 파일( security_protocols.py
)의 절대 경로와 줄 번호 7
입니다. in <module></module>
문은 코드가 함수 외부에 있음을 의미합니다. 이 예에서 콜백은 한 단계에 불과하므로 좀 더 복잡한 것을 살펴보겠습니다. 이전 코드를 변경하고 확장했습니다. 🎜
def get_datafile_id(subject): try: id = datafile_index[subject] print(f"See datafile {id}.") except KeyError: print(f"Datafile not found on {subject}")
전과 비슷한 오류가 발생했습니다. 문자열을 정수로 변환하려고 했지만 작동하지 않았습니다. 두 번째 줄은 실패한 코드를 보여줍니다. 확실히 int()
에 대한 참조가 있습니다. 위 줄에 따르면 문제가 있는 코드는 security_protocols.py
파일의 2번째 줄에 있는 initiate_security_protocol()
함수 내부에 있습니다! 바로 찾아 try...excess
로 래핑할 수 있습니다. 아래에서 위로 읽으면 시간이 절약되는 이유를 이해하시나요? 🎜
然而,让我们想象它并不那么简单。也许我们没有修改security_protocols.py
的选项,所以我们需要在执行该模块之前防止出现问题。如果我们查看下一行,我们会看到在databank.py
第 4 行,在decode_message()
函数内部,我们调用的initiate_security_protocol()
函数有问题。是由于在databank.py
第6行被调用,这就是我们将参数传递"Bad Wolf"
给它的地方。
数据输入不是问题,因为我们要解码消息“Bad Wolf”。但是,为什么我们要将我们试图解码的消息传递给安全协议呢?也许我们需要改写那个函数(或者除了其他更改之外?)。如你所见,Traceback对于了解错误的来源非常重要。养成仔细阅读的习惯;许多有用的信息可能隐藏在意想不到的地方。
顺便说一句,第一行每次都是一样的,但是如果你忘记如何阅读这些消息,它会非常有用。最近执行的代码列在最后。因此,正如我之前所说,你应该从下往上阅读它们。
Exception
“请求宽恕比获得许可更容易。” -海军少将格蕾丝·霍珀
这句话最初是关于主动的;如果你相信一个想法,请尽力去尝试它,而不是等待其他人的许可来追求它。然而,在这种情况下,它很好地描述了 Python 的错误处理哲学:如果某些事情经常以一种或多种特定方式失败,通常最好使用<strong>try...except</strong>
语句来处理这些情况。
这种哲学被正式命名为“请求宽恕比许可更容易”,或EAFP。
这有点抽象,所以让我们考虑另一个例子。假设我们希望能够在字典中查找信息。
datafile_index = { # Omitted for brevity. # Just assume there's a lot of data in here. } def get_datafile_id(subject): id = datafile_index[subject] print(f"See datafile {id}.") get_datafile_id("Clara Oswald") get_datafile_id("Ashildir")
See datafile 6035215751266852927. Traceback (most recent call last): File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 30, in <module> get_datafile_id("Ashildir") File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/databank.py", line 26, in get_datafile_id id = datafile_index[subject] KeyError: 'Ashildir'</module>
第一个函数调用是对的。我们在字典database_index
中搜索存在的键"Clara Oswald"
,因此我们返回与其关联的值 (6035215751266852927
),并在我们格式化语句print()
中打印出该数据。但是,第二个函数调用失败。引发异常KeyError
,因为"Ashildir"
它不是字典中的键。
技术说明: Python 为collections.defaultdict
这个确切问题提供了另一种解决方案;尝试访问不存在的键将使用一些默认值在字典中创建键/值对。但是,由于这是演示错误处理的示例,因此我没有使用它。
由于不能合理地期望我们知道或记住字典中的所有键,尤其是在现实世界的场景中,我们需要一些方法来处理尝试访问不存在的键的常见情况。你的第一直觉可能是在尝试访问字典键之前检查它......
def get_datafile_id(subject): if subject in datafile_index: id = datafile_index[subject] print(f"See datafile {id}.") else: print(f"Datafile not found on {subject})
在 Python 文化中,这种方法被称为“跳前看”[LBYL]。
但这不是最有效的方法!“宽恕,而不是许可”在这里发挥作用:我们不是先测试,而是使用<strong>try...except</strong>
.
def get_datafile_id(subject): try: id = datafile_index[subject] print(f"See datafile {id}.") except KeyError: print(f"Datafile not found on {subject}")
这背后的逻辑很简单:我们不是通过两次获取键,而是只访问一次,并使用实际exception作为逻辑分支的手段。
在 Python 中,我们不认为异常是可以避免的。事实上,try...except
它是许多 Python 设计模式和算法的常规部分。不要害怕引发和捕获异常!事实上,即使是键盘中断也是通过KeyboardInterrupt
异常处理的。
注意: try...except
是一个强大的工具,但它并不适用于一切。例如,None
从函数返回通常被认为比引发异常更好。仅在发生最好由调用者处理的实际错误时抛出异常。
反面模式
迟早,每个 Python 开发人员都会发现这是可行的:
try: someScaryFunction() except: print("An error occured. Moving on!")
一个单except
语句允许你在一个中捕获所有异常。这个被称为反面模式,这是一个非常非常糟糕的想法。总结一下……
...实际错误的所有上下文放在了一起抛出,永远看不到问题跟踪器的内部。当发生“大量”异常时,堆栈跟踪指向发生次要错误的位置,而不是 try 块内的实际失败位置。
长话短说,你应该始终明确地捕获特定的异常类型。任何你无法预见的失败都可能与一些需要解决的错误有关;例如,当你的超级复杂搜索功能突然开始提出 anOSError
而不是预期的KeyError
或者TypeError
时。
像往常一样,The Zen Python 对此有话要说……
错误永远不应该悄无声息地过去。
除非明确沉默。
换句话说,这不是口袋妖怪 - 你不应该抓住他们!
Except, Else, Finally
我不会一下子就捕捉到所有异常。那么,如何处理多个可能的故障呢?
你要知道 Python 的try...except
工具比它最初展示的要多得多。
class SonicScrewdriver: def __init__(self): self.memory = 0 def perform_division(self, lhs, rhs): try: result = float(lhs)/float(rhs) except ZeroDivisionError: print("Wibbly wobbly, timey wimey.") result = "Infinity" except (ValueError, UnicodeError): print("Oy! Don't diss the sonic!") result = "Cannot Calculate" else: self.memory = result finally: print(f"Calculation Result: {result}\n") sonic = SonicScrewdriver() sonic.perform_division(8, 4) sonic.perform_division(4, 0) sonic.perform_division(4, "zero") print(f"Memory Is: {sonic.memory}")
在我向你展示输出之前,请仔细查看代码。你认为这三个sonic.perform_division()
函数调用中的每一个都会打印出什么?最终存储sonic.memory
的是什么?看看你能不能弄明白。
如果你已经有答案?让我们看看你是否正确。
Calculation Result: 2.0 Wibbly wobbly, timey wimey. Calculation Result: Infinity Oy! Don't diss the sonic! Calculation Result: Cannot Calculate Memory Is: 2.0
你是惊讶,还是你做对了?让我们分析一下。
try:
当然,是我们试图运行的代码,它可能会也可能不会引发异常。
except ZeroDivisionError:
当我们试图除以零时发生。在这种情况下,我们说该值"Infinity"
是计算的结果,并打印出一条关于除以0的提示信息。
except (ValueError, UnicodeError):
只要引发这两个异常之一,就会抛出异常。ValueError
是每当我们传递的任何参数都不能被强制转换float()
时,就会发生这种错误,而UnicodeError
是如果编码或解码 Unicode 有问题,就会发生这种报错。实际上,第二个只是为了说明一点。对于ValueError
所有无法将参数转换为浮点数的可信场景,这已经足够了。无论哪种情况,我们都将值"Cannot Calculate"
作为我们的结果,并提醒用户不要对硬件提出不合理的要求。
这就是事情变得有趣的地方。仅在未引发异常时else:
运行。在这种情况下,如果我们有一个有效的除法计算结果,我们实际上希望将它存储在内存中;相反,如果我们得到“无穷大”或“无法计算”作为我们的结果,我们不会存储它。
无论如何,该finally:
部分都会运行。在这种情况下,我们打印出我们的计算结果。
顺序确实很重要。我们必须遵循模式try...except...else...finally
,else
如果存在,必须在所有except
语句之后。finally
总是最后的。
最初很容易混淆else
和finally
,因此请确保你了解其中的区别。<strong>else</strong>
仅在未引发异常时运行;<strong>finally</strong>
每次运行。
Finally执行顺序
你希望以下代码实现什么?
class SonicScrewdriver: def __init__(self): self.memory = 0 def perform_division(self, lhs, rhs): try: result = float(lhs)/float(rhs) except ZeroDivisionError: print("Wibbly wobbly, timey wimey.") result = "Infinity" except (ValueError, UnicodeError): print("Oy! Don't diss the sonic!") result = "Cannot Calculate" else: self.memory = result return result finally: print(f"Calculation Result: {result}\n") result = -1 sonic = SonicScrewdriver() print(sonic.perform_division(8, 4))
下面的那return
句话else
应该是事情的结束了吧?其实,不!如果我们运行该代码...
Calculation Result: 2.0 2.0
有两个重要的观察结果:
finally
正在运行,即使在我们的return
声明之后。该函数不会像通常那样退出。该
return
语句确实在finally
块执行之前运行。我们知道这一点是因为结果result
输出是2.0
,而不是我们在语句finally
中分配的-1
。
<strong>finally</strong>
每次都会运行,即使你<strong>return</strong>
在<strong>try...except</strong>
结构中的其他地方有。
但是,我也用一个os.abort()
代替测试了上面的return result
,在这种情况下,finally
块永远不会运行;该程序彻底中止。你可以在任何地方直接停止程序执行,Python 只会放弃它正在做的事情并退出。该规则是不变的,即使是不寻常的finally
行为。
抛出异常
所以,我们可以用try...except
捕获异常. 但是如果我们只是想主动抛出一个呢?
在 Python 术语中,我们说我们引发了异常,并且与该语言中的大多数事情一样,实现这一点很明显:只需使用raise
关键字:
class Tardis: def __init__(self): pass def camouflage(self): raise NotImplementedError('Chameleon circuits are stuck.') tardis = Tardis() tardis.camouflage()
当我们执行该代码时,我们会看到我们引发的异常。
Traceback (most recent call last): File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/tardis.py", line 10, in <module> tardis.camoflague() File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/tardis.py", line 7, in camoflague raise NotImplementedError('Chameleon circuits are stuck.') NotImplementedError: Chameleon circuits are stuck.</module>
这样就能知道我们在哪儿出现了异常错误。
注意:异常NotImplementedError是Python 中的内置异常之一,有时用于指示一个函数不应该使用,因为它还没有完成(但总有一天会完成)。它不能与NotImplementedvalue互换。请参阅文档以了解何时使用它们。
显然,关键代码是raise NotImplementedError('Chameleon circuits are stuck.')
. 在raise
关键字之后,我们给出要引发的异常对象的名称。在大多数情况下,我们从 Exception 类创建一个新对象,从括号的使用可以看出。所有异常都接受字符串作为消息的第一个参数。一些例外接受或需要更多参数,因此请参阅官方文档。
使用异常
有时我们需要在捕捉到异常后对其进行处理。我们有一些非常简单的方法来做到这一点。
最明显的是从异常中打印消息。为此,我们需要能够处理我们捕获的异常对象。让我们将except
语句更改为except NotImplementedError as e:
,其中e
是我们“绑定”到异常对象的名称。然后,我们可以e
直接作为对象使用。
tardis = Tardis() try: tardis.camouflage() except NotImplementedError as e: print(e)
异常类已经定义了它的__str__()
函数来返回异常消息,所以如果我们将它转换成一个字符串(str()
),这就是我们将得到的。你可能还记得上一篇文章print()
自动将其参数转换为字符串。当我们运行这段代码时,我们得到...
Chameleon circuits are stuck.
是不是很容易!
冒泡
现在,如果我们想再次引发异常怎么办?
等等,什么?我们刚刚捕获了那个东西。为什么还要再次引发异常?
一个示例是,如果你需要在幕后进行一些清理工作,但最终仍希望调用者必须处理异常。这是一个例子......
class Byzantium: def __init__(self): self.power = 0 def gravity_field(self): if self.power <p data-id="p838747a-oxRDqDnA">在上面的示例中,我们只是想捕获一些实体 ( <code>grab_handle()</code>) 并打印一条附加消息,然后让异常继续<code>raise</code>抛出. 当我们重新引发异常时,我们说它<strong>冒泡了</strong>。</p><pre class="brush:php;toolbar:false">Night night Traceback (most recent call last): File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/byzantium.py", line 18, in <module> byzantium.gravity_field() File "/home/jason/Code/FiringRanges/PyFiringRange/Sandbox/byzantium.py", line 8, in gravity_field raise SystemError("Gravity Failing") SystemError: Gravity Failing</module>
注意:你可能认为我们需要说except SystemError as e:
或者说raise e
什么,但那是矫枉过正。对于冒泡的异常,我们只需要自己调用<strong>raise</strong>
。
现在,如果我们想在冒泡异常的同时添加一些额外的信息怎么办?你的第一个猜测可能只是完全引发一个新异常,但这会带来一些问题。为了演示,我将在执行顺序中添加另一层。请注意,当我处理这个问题时SystemError
,我会提出一个新的RuntimeError
。我在第二个try...except
区块中发现了这个新异常。
byzantium = Byzantium() def test(): try: byzantium.gravity_field() except SystemError: grab_handle() raise RuntimeError("Night night") try: test() except RuntimeError as e: print(e) print(e.__cause__)
当我们运行它时,我们得到以下输出。
Night night None
当我们捕获到这个新异常时,我们完全没有关于它是什么原因的上下文。为了解决这个问题,Python 3在PEP 3134中引入了显式异常链接。实现它很容易。看看我们的新函数test()
,这是我与上一个示例相比唯一更改的部分。
byzantium = Byzantium() def test(): try: byzantium.gravity_field() except SystemError as e: grab_handle() raise RuntimeError("Night night") from e try: test() except RuntimeError as e: print(e) print(e.__cause__)
你有没有发现我在那儿做什么?在except
声明中,我将名称绑定e
到我们捕获的原始异常。然后,在引发新RuntimeError
异常时,我将其链接到上一个异常,并使用from e
. 我们现在的输出...
Night night Gravity Failing
当我们运行它时,我们的新异常会记住它是从哪里来的——前一个异常存储在它的__cause__
属性中(打印在输出的第二行)。这对于日志记录特别有用。
你可以使用异常类执行许多其他技巧,尤其是在引入 PEP 3134 时。像往常一样,我建议你阅读文档,我在文章末尾链接到该文档。
自定义异常
Python 有一大堆异常,它们的使用有据可查。当我为工作选择合适的异常时,我经常参考这个异常列表。然而,有时,我们只需要更多……定制的东西。
所有错误类型的异常都是从Exception
类派生的,而类又是从BaseException
类派生的。这种双重层次结构的原因是你可以捕获所有错误Exceptions
,而无需对特殊的、非系统退出的异常(如KeyboardInterrupt
. 当然,这在实践中对你来说并不重要,因为except Exception
实际上总是我之前提到的反模式的另一种形式。无论如何,不建议你直接派生自BaseException
——只要知道它存在即可。
在进行自定义异常时,你实际上可以从任何你喜欢的异常类派生。有时,最好从与你正在自定义的异常最接近的异常中获取。但是,如果你不知所措,你可以从Exception
派生.
让我们自定义一个,好吗?
class SpacetimeError(Exception): def __init__(self, message): super().__init__(message) class Tardis(): def __init__(self): self._destination = "" self._timestream = [] def cloister_bell(self): print("(Ominous bell tolling)") def dematerialize(self): self._timestream.append(self._destination) print("(Nifty whirring sound)") def set_destination(self, dest): if dest in self._timestream: self.cloister_bell() self._destination = dest def engage(self): if self._destination in self._timestream: raise SpacetimeError("You should not cross your own timestream!") else: self.dematerialize() tardis = Tardis() # Should be fine tardis.set_destination("7775/349x10,012/acorn") tardis.engage() # Also fine tardis.set_destination("5136/161x298,58/delta") tardis.engage() # The TARDIS is not going to like this... tardis.set_destination("7775/349x10,012/acorn") tardis.engage()
显然,最后一个将导致我们的SpacetimeError
异常被引发。
让我们再看看那个异常类声明。
class SpacetimeError(Exception): def __init__(self, message): super().__init__(message)
这实际上非常容易编写。如果你还记得我们之前对类的探索,super().__init__()
就是在基类上调用初始化函数,Exception
在这种情况下就是这样。我们将消息传递给SpacetimeError
异常构造函数,并将其交给基类初始化函数。
事实上,如果我唯一要做的就是将 传递message
给super()
, 类,我可以让这更简单:
class SpacetimeError(Exception): pass
Python 自己处理基础异常。
这就是我们需要做的所有事情,尽管像往常一样,我们可以用这个做更多的技巧。自定义异常不仅仅是一个漂亮的名字;我们可以使用它们来处理各种不寻常的错误场景,尽管这显然超出了本指南的范围。
위 내용은 Python 오류 예외를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

2 시간 이내에 Python의 기본 프로그래밍 개념과 기술을 배울 수 있습니다. 1. 변수 및 데이터 유형을 배우기, 2. 마스터 제어 흐름 (조건부 명세서 및 루프), 3. 기능의 정의 및 사용을 이해하십시오. 4. 간단한 예제 및 코드 스 니펫을 통해 Python 프로그래밍을 신속하게 시작하십시오.

Python은 웹 개발, 데이터 과학, 기계 학습, 자동화 및 스크립팅 분야에서 널리 사용됩니다. 1) 웹 개발에서 Django 및 Flask 프레임 워크는 개발 프로세스를 단순화합니다. 2) 데이터 과학 및 기계 학습 분야에서 Numpy, Pandas, Scikit-Learn 및 Tensorflow 라이브러리는 강력한 지원을 제공합니다. 3) 자동화 및 스크립팅 측면에서 Python은 자동화 된 테스트 및 시스템 관리와 같은 작업에 적합합니다.

2 시간 이내에 파이썬의 기본 사항을 배울 수 있습니다. 1. 변수 및 데이터 유형을 배우십시오. 이를 통해 간단한 파이썬 프로그램 작성을 시작하는 데 도움이됩니다.

10 시간 이내에 컴퓨터 초보자 프로그래밍 기본 사항을 가르치는 방법은 무엇입니까? 컴퓨터 초보자에게 프로그래밍 지식을 가르치는 데 10 시간 밖에 걸리지 않는다면 무엇을 가르치기로 선택 하시겠습니까?

Fiddlerevery Where를 사용할 때 Man-in-the-Middle Reading에 Fiddlereverywhere를 사용할 때 감지되는 방법 ...

Python 3.6에 피클 파일로드 3.6 환경 보고서 오류 : modulenotfounderror : nomodulename ...

경치 좋은 스팟 댓글 분석에서 Jieba Word 세분화 문제를 해결하는 방법은 무엇입니까? 경치가 좋은 스팟 댓글 및 분석을 수행 할 때 종종 Jieba Word 세분화 도구를 사용하여 텍스트를 처리합니다 ...

정규 표현식을 사용하여 첫 번째 닫힌 태그와 정지와 일치하는 방법은 무엇입니까? HTML 또는 기타 마크 업 언어를 다룰 때는 정규 표현식이 종종 필요합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기

안전한 시험 브라우저
안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.
