{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 20. None을 반환하기보다는 예외를 발생시켜라" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "def careful_divide(a, b):\n", " try:\n", " return a / b\n", " except ZeroDivisionError:\n", " return None" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "x, y = 1, 0" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "result = careful_divide(x, y)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "error\n" ] } ], "source": [ "if result is None:\n", " print('error')" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "error\n" ] } ], "source": [ "if not result:\n", " print('error')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "False와 동등한 반환 값을 잘못 해석하는 경우는 None이 특별한 의미를 가지는 파이썬 코드에서 흔히 저지르는 실수이다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "실수 가능성을 줄이는 방법 두가지" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. 2-튜플로 분리하는 것 \n", "첫 번째 부분은 연산이 성공인지 실패인지 표시, 두번째 부분은 성공시 결과 값" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def careful_divide(a, b):\n", " try:\n", " return True, a / b\n", " except ZeroDivisionError:\n", " return False, None" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "success, result = careful_divide(x, y)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "error\n" ] } ], "source": [ "if not success:\n", " print('error')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "문제점은 첫번째를 무시할수 있다는 점" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "error\n" ] } ], "source": [ "_, result = careful_divide(x, y)\n", "if not success:\n", " print('error')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이런 실수를 줄일 수 있는 더 나은 두번째 방법 \n", "2. None을 반환하지 않는 것" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def careful_divide(a, b):\n", " try:\n", " return a / b\n", " except ZeroDivisionError as e:\n", " raise ValueError('error')" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "결과는 2.5 입니다\n" ] } ], "source": [ "x, y = 5, 2\n", "try:\n", " result = careful_divide(x, y)\n", "except ValueError as e:\n", " print(e)\n", "else:\n", " print('결과는 %.1f 입니다' % result)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "error\n" ] } ], "source": [ "x, y = 5, 0\n", "try:\n", " result = careful_divide(x, y)\n", "except ValueError as e:\n", " print(e)\n", "else:\n", " print('결과는 %.1f 입니다' % result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이 방법을 확장해서 타입 애너테이션을 사용하는 코드에도 적용이 가능하다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "독스트링과 타입 애너테이션까지 포함시키면 다음과 같다" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "def careful_divide(a: float, b: float) -> float:\n", " \"\"\"a를 b로 나눈다.\n", " \n", " Raises:\n", " ValueError: b가 0이어서 나눗셈을 할 수 없을 때\n", " \"\"\"\n", " try:\n", " return a / b\n", " except ZeroDivisionError as e:\n", " raise ValueError('error')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 기억해야 할 내용\n", "- 특별한 의미를 표시하는 None을 반환하는 함수를 사용하면 None과 다른 값(0 이나 빈 문자열)이 조건문에서 False로 평가될 수 있기 때문에 실수하기 쉽다.\n", "- 특별한 상황을 표현하기 위해 None을 반환하는 대신 예외를 발생시켜라. 문서에 예외 정보를 기록해 호출자가 예외를 제대로 처리하도록 하라.\n", "- 함수가 특별한 경우를 포함하는 그 어떤 경우에도 절대로 None을 반환하지 않는다는 사실을 타입 애너테이션으로 명시할 수 있다." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.7.6" } }, "nbformat": 4, "nbformat_minor": 4 }