{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 22. 변수 위치 인자를 사용해 시각적인 잡음을 줄여라" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "위치 인자 (Positional argument) 를 가변적으로 받을 수 있으면 함수 호출이 더 깔끔해지고 시각적 잡음도 줄어든다." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def log(message, values):\n", " if not values:\n", " print(message)\n", " else:\n", " values_str = ', '.join(str(x) for x in values)\n", " print(f'{message}: {values_str}')" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "내 숫자는: 1, 2\n" ] } ], "source": [ "log('내 숫자는', [1, 2])" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "안녕\n" ] } ], "source": [ "log('안녕', [])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "빈 리스트를 넘겨야 한다면 귀찮음 뿐만 아니라 잡음이 많다.\n", "\n", "생략 가능하도록 하자" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def log(message, *values):\n", " if not values:\n", " print(message)\n", " else:\n", " values_str = ', '.join(str(x) for x in values)\n", " print(f'{message}: {values_str}')" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "내 숫자는: 1, 2\n" ] } ], "source": [ "log('내 숫자는', 1, 2)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "안녕\n" ] } ], "source": [ "log('안녕')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "언패킹 대입문에 쓰인 별표식과 비슷함\n", "\n", "시퀀스를 사용하고 싶다면 * 연산자를 사용하면 된다." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "내 숫자는: 1, 2, 3\n" ] } ], "source": [ "favorite = [1, 2, 3]\n", "log('내 숫자는', *favorite)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "내 숫자는: [1, 2, 3]\n" ] } ], "source": [ "favorite = [1, 2, 3]\n", "log('내 숫자는', favorite)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "가변적인 위치 인자를 받는 데는 두 가지 문제점이 있다.\n", "\n", "첫번째 : 선택적인 위치 인자가 함수에 전달되기 전에 항상 튜플로 변환됨\n", "\n", "메모리를 아주 많이 소비하거나 프로그램이 중단될 수 있음." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "def my_generator():\n", " for i in range(10):\n", " yield i" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "def my_func(*args):\n", " print(args)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "it = my_generator()" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)\n" ] } ], "source": [ "my_func(*it)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "두 번째 문제점은 새로운 위치 인자를 추가하면 해당 함수를 호출하는 모든 코드를 변경해야 한다." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "def log(sequence, message, *values):\n", " if not values:\n", " print(f'{sequence} - {message}')\n", " else:\n", " values_str = ', '.join(str(x) for x in values)\n", " print(f'{sequence} - {message}: {values_str}')" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 - 좋아하는 숫자는: 7, 33\n" ] } ], "source": [ "log(1, '좋아하는 숫자는', 7, 33)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 - 안녕\n" ] } ], "source": [ "log(1, '안녕')" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "좋아하는 숫자는 - 7: 33\n" ] } ], "source": [ "log('좋아하는 숫자는', 7, 33)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "이런 가능성을 완전히 없애려면 \\*args를 받아들이는 함수를 확장할 떄는 키워드 기반의 인자만 사용해야 한다. (Better way 25)\n", "\n", "더 방어적으로 프로그래밍하려면 타입 애너테이션 (Better way 90)을 사용해도 된다." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 기억해야 할 내용\n", "- def 문에서 \\*args를 사용하면 함수가 가변 위치 인자를 받을 수 있다.\n", "- \\* 연산자를 사용하면 가변 인자를 받는 함수에게 시퀀스 내의 원소들을 전달할 수 있다.\n", "- 제너레이터에 \\* 연산자를 사용하면 프로그램이 메모리를 모두 소진하고 중단될 수 있다.\n", "- \\*args를 받는 함수에 새로운 위치 기반 인자를 넣으면 감지하기 힘든 버그가 생길 수 있다." ] } ], "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.8.2" } }, "nbformat": 4, "nbformat_minor": 4 }