{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "*이 노트북은 제이크 반더플라스(Jake VanderPlas)의 [A Whirlwind Tour of Python](http://www.oreilly.com/programming/free/a-whirlwind-tour-of-python.csp)(OReilly Media, 2016)를 기반으로 만들어졌습니다. 이 내용은 [CC0](https://github.com/jakevdp/WhirlwindTourOfPython/blob/master/LICENSE) 라이센스를 따릅니다. 전체 노트북의 목록은 https://github.com/rickiepark/WhirlwindTourOfPython 에서 볼 수 있습니다.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "< [함수](08-함수.ipynb) | [목차](목차.ipynb) | [반복자](10-반복자.ipynb) >" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 에러와 예외처리" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "프로그래머로서의 기술에 상관없이 코딩 실수는 하기 마련입니다. 여기에는 세 종류의 실수가 있습니다:\n", "\n", "- *문법 에러*: 파이썬 문법에 맞지 않는 코드로 인한 에러(일반적으로 고치기 쉽습니다)\n", "- *실행 에러*: 문법적으로는 옳지만 실행시에 나는 에러, 아마도 잘못된 입력 때문입니다(고치기 쉬운 편입니다)\n", "- *논리 에러*: 문제없이 코드가 실행되지만 원치않는 결과가 나옵니다(종종 고치기 매우 어렵습니다)\n", "\n", "여기에서는 어떻게 실행시 에러를 깔끔하게 다루는지 배웁니다. 파이썬은 *예외처리 핸들링* 프레임워크로 실행시 에러를 처리합니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 실행 에러\n", "파이썬 코딩을 해보았다면 실행 에러를 만난 적이 있을 것입니다. 이 에러는 다양한 곳에서 일어 납니다.\n", "\n", "예를 들어, 정의되어 있지 않은 변수를 참조할 때 발생합니다:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'Q' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m\u001b[0m", "\u001b[0;31mNameError\u001b[0mTraceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mQ\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'Q' is not defined" ] } ], "source": [ "print(Q)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "또는 정의되지 않은 연산을 시도할 때입니다:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for +: 'int' and 'str'", "output_type": "error", "traceback": [ "\u001b[0;31m\u001b[0m", "\u001b[0;31mTypeError\u001b[0mTraceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m'abc'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'" ] } ], "source": [ "1 + 'abc'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "또는 수학적으로 계산할 수 없는 연산을 시도할 때입니다:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "ename": "ZeroDivisionError", "evalue": "division by zero", "output_type": "error", "traceback": [ "\u001b[0;31m\u001b[0m", "\u001b[0;31mZeroDivisionError\u001b[0mTraceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m2\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" ] } ], "source": [ "2 / 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "또는 존재하지 않는 원소에 접근할 때입니다:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "ename": "IndexError", "evalue": "list index out of range", "output_type": "error", "traceback": [ "\u001b[0;31m\u001b[0m", "\u001b[0;31mIndexError\u001b[0mTraceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mL\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mL\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1000\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mIndexError\u001b[0m: list index out of range" ] } ], "source": [ "L = [1, 2, 3]\n", "L[1000]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "각 경우에 파이썬은 단순히 에러가 일어난 것을 알려주는 것 뿐만 아니라 정확히 무엇이 잘못 되었는지 에러가 발생한 코드의 위치는 어디인지의 정보를 포함한 의미있는 예외를 발생시킵니다.\n", "이런 에러의 의미를 사용하면 코드에 있는 문제를 찾아가는데 매우 도움이 됩니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 예외 처리: ``try``와 ``except``\n", "실행시 예외를 다루기 위한 도구는 ``try``...``except`` 절입니다.\n", "기본 구조는 다음과 같습니다:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "먼저 이 라인이 실행됩니다\n" ] } ], "source": [ "try:\n", " print(\"먼저 이 라인이 실행됩니다\")\n", "except:\n", " print(\"에러가 발생할 때 실행됩니다\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "첫 번째 블럭에서 에러가 발생하지 않았기 때문에 두 번째 블럭은 실행되지 않습니다.\n", "``try`` 블럭안에 잘못된 코드를 넣으면 어떻게 되는지 보겠습니다:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "다음 코드를 실행합니다:\n", "무언가 잘못되었습니다!\n" ] } ], "source": [ "try:\n", " print(\"다음 코드를 실행합니다:\")\n", " x = 1 / 0 # ZeroDivisionError\n", "except:\n", " print(\"무언가 잘못되었습니다!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "``try`` 문 안에서 에러가 발생하면(여기서는 ``ZeroDivisionError``) 캐치되어 ``except`` 문이 실행됩니다.\n", "\n", "함수나 코드에서 사용자의 입력을 체크하는데 자주 사용하는 방법입니다. \n", "예를 들어 0으로 나누는 에러를 캐치하여 $10^{100}$와 같이 아주 충분히 큰 값을 반환하는 함수를 만들 수 있습니다:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def safe_divide(a, b):\n", " try:\n", " return a / b\n", " except:\n", " return 1E100" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.5" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "safe_divide(1, 2)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1e+100" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "safe_divide(2, 0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이 함수에는 교묘한 문제가 있습니다. 다른 종류의 예외가 발생하면 어떻게 될까요? 가령, 다음은 예상하지 못한 상황입니다:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1e+100" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "safe_divide (1, '2')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "정수와 문자열을 사용해 나눗셈을 하면 ``TypeError``가 발생됩니다. 이 에러도 과도하게 캐치하여 ``ZeroDivisionError``로 간주하는 셈이 됩니다!\n", "이런 이유 때문에 명시적으로 캐치할 예외를 지정하는 것이 좋습니다:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def safe_divide(a, b):\n", " try:\n", " return a / b\n", " except ZeroDivisionError:\n", " return 1E100" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1e+100" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "safe_divide(1, 0)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for /: 'int' and 'str'", "output_type": "error", "traceback": [ "\u001b[0;31m\u001b[0m", "\u001b[0;31mTypeError\u001b[0mTraceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0msafe_divide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'2'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36msafe_divide\u001b[0;34m(a, b)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0msafe_divide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mZeroDivisionError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1E100\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for /: 'int' and 'str'" ] } ], "source": [ "safe_divide(1, '2')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이제 0으로 나누는 에러만 캐치하고 나머지 에러는 그냥 통과시킵니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 예외 발생: ``raise``\n", "파이썬을 사용할 때 예외에 담긴 정보가 얼마나 유용한지 보았습니다.\n", "여러분이 작성한 코드에서도 유용한 예외는 동일한 가치가 있습니다. 이렇게 하면 코드를 사용할 사용자(무엇보다도 자기자신!)가 에러가 발생된 원인을 쉽게 찾을 수 있습니다.\n", "\n", "자기자신의 예외를 발생시키는 방법은 ``raise`` 문을 사용하는 것입니다. 예를 들어:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "ename": "RuntimeError", "evalue": "my error message", "output_type": "error", "traceback": [ "\u001b[0;31m\u001b[0m", "\u001b[0;31mRuntimeError\u001b[0mTraceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"my error message\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mRuntimeError\u001b[0m: my error message" ] } ], "source": [ "raise RuntimeError(\"my error message\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이에 대한 유용한 예를 위해서 앞서 정의한 ``fibonacci`` 함수로 돌아가 보죠:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "def fibonacci(N):\n", " L = []\n", " a, b = 0, 1\n", " while len(L) < N:\n", " a, b = b, a + b\n", " L.append(a)\n", " return L\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이 함수에서 한 가지 문제점은 입력값이 음수일 수 있다는 것입니다.\n", "음수가 입력되어도 이 함수에서 어떤 에러도 발생시키지는 않습니다. 하지만 음수 ``N``을 지원하지 않는다는 점을 사용자에게 알리고 싶습니다.\n", "관례적으로 잘못된 파라미터 값에의해 발생한 에러는 ``ValueError``를 발생시킵니다:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "def fibonacci(N):\n", " if N < 0:\n", " raise ValueError(\"N은 음수가 아니어야 합니다\")\n", " L = []\n", " a, b = 0, 1\n", " while len(L) < N:\n", " a, b = b, a + b\n", " L.append(a)\n", " return L" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fibonacci(10)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "N은 음수가 아니어야 합니다", "output_type": "error", "traceback": [ "\u001b[0;31m\u001b[0m", "\u001b[0;31mValueError\u001b[0mTraceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfibonacci\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36mfibonacci\u001b[0;34m(N)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mfibonacci\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mN\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mN\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"N은 음수가 아니어야 합니다\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0mL\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValueError\u001b[0m: N은 음수가 아니어야 합니다" ] } ], "source": [ "fibonacci(-10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이제 사용자는 왜 입력이 잘못되었는지 정확히 알게됩니다. 심지어 ``try``...``except`` 블럭을 사용하여 이를 캐치할 수 있습니다!" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "피보나치를 시도..\n", "잘못된 값: 무언가 다른 조치가 필요하다\n" ] } ], "source": [ "N = -10\n", "try:\n", " print(\"피보나치를 시도..\")\n", " print(fibonacci(N))\n", "except ValueError:\n", " print(\"잘못된 값: 무언가 다른 조치가 필요하다\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 예외에 대해 자세히 알아보기\n", "간단히 앞으로 볼 수 있는 다른 개념에 대해 언급하겠습니다.\n", "너무 자세한 개념이나 왜, 어떻게 사용하는지 설명하지 않겠습니다. 대신 간단한 사용법을 보이고 나중에 스스로 더 찾아보도록 돕겠습니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 에러 메세지 참조\n", "``try``...``except`` 문에서 이따금 에러 메세지 자체를 다루어야할 때가 있습니다.\n", "이럴 때는 ``as`` 키워드를 사용합니다:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "에러 클래스: \n", "에러 메세지: division by zero\n" ] } ], "source": [ "try:\n", " x = 1 / 0\n", "except ZeroDivisionError as err:\n", " print(\"에러 클래스: \", type(err))\n", " print(\"에러 메세지:\", err)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이 패턴을 사용해 함수의 예외 처리를 다양하게 커스터마이징할 수 있습니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 독자적인 예외 정의하기\n", "기본 예외말고도 클래스 상속을 통해 독자적인 예외를 정의할 수 있습니다. 예를 들어 특별한 종류의 ``ValueError``가 필요하면 다음과 같이 씁니다:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "ename": "MySpecialError", "evalue": "here's the message", "output_type": "error", "traceback": [ "\u001b[0;31m\u001b[0m", "\u001b[0;31mMySpecialError\u001b[0mTraceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mpass\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mMySpecialError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"here's the message\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mMySpecialError\u001b[0m: here's the message" ] } ], "source": [ "class MySpecialError(ValueError):\n", " pass\n", "\n", "raise MySpecialError(\"here's the message\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이 에러만 캐치하는 ``try``...``except`` 블럭을 사용할 수 있습니다:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "작업 수행\n", "다른 작업 수행\n" ] } ], "source": [ "try:\n", " print(\"작업 수행\")\n", " raise MySpecialError(\"[상세한 에러 정보]\")\n", "except MySpecialError:\n", " print(\"다른 작업 수행\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "커스터마이징이 많이 필요한 코드일수록 이 용법이 유용합니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ``try``...``except``...``else``...``finally``\n", "``try``와 ``except`` 외에 ``else``와 ``finally`` 키워드를 사용해 예외 처리를 정교하게 튜닝할 수 있습니다.\n", "기본적인 구조는 다음과 같습니다:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "어떤 작업을 시도합니다\n", "성공할 경우 실행됩니다\n", "무조건 실행됩니다\n" ] } ], "source": [ "try:\n", " print(\"어떤 작업을 시도합니다\")\n", "except:\n", " print(\"실패할 경우 실행됩니다\")\n", "else:\n", " print(\"성공할 경우 실행됩니다\")\n", "finally:\n", " print(\"무조건 실행됩니다\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "``else``의 용도는 명확하지만 ``finally``는 왜 필요할까요?\n", "글쎄요, ``finally`` 절은 실제로 에러가 있던 없던 실행됩니다. 보통 어떤 작업이 완료되고 나서 자원을 정리하는 경우에 사용되곤 합니다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "< [함수](08-함수.ipynb) | [목차](목차.ipynb) | [반복자](10-반복자.ipynb) >" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "TensorFlow 2.3 on Python 3.6 (CUDA 10.1)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" } }, "nbformat": 4, "nbformat_minor": 1 }