├── .gitignore ├── README.md ├── day1 ├── 1_args.ipynb └── 2_firstclass_function.ipynb ├── day2 ├── .ipynb_checkpoints │ ├── 3_decorator-checkpoint.ipynb │ └── mutation-checkpoint.ipynb ├── 3_decorator.ipynb ├── 4_Generator.ipynb ├── 4_Iterator.ipynb ├── 5_set.ipynb ├── 6_mutation.ipynb └── 8_scope │ ├── 8_scope.ipynb │ ├── __pycache__ │ ├── first.cpython-36.pyc │ └── thismod.cpython-36.pyc │ ├── data.txt │ ├── first.py │ ├── img │ └── scope_diagram.jpg │ └── thismod.py ├── day3 ├── 09_ternary_op.ipynb ├── 10_lambda_functions.ipynb ├── 10_lambda_time.ipynb ├── 11_Comprehension.ipynb ├── 12_For-else.ipynb ├── 13_collections.ipynb ├── 13_enumerate.ipynb └── 14___slots__.ipynb ├── day4 ├── 15_debugging.ipynb ├── 15_unittest.ipynb ├── 16_virtualenv.ipynb ├── 17_logging.ipynb ├── Exception.ipynb ├── Profiling.ipynb ├── auxiliary_module.py ├── employeelogger.py ├── garbage collection.ipynb ├── mylib.py ├── profiler_test1.py └── profiler_test2.py ├── day5 ├── 22_open.ipynb ├── map_reduce_filter.ipynb ├── multiprocessing.ipynb ├── multiprocessing.py └── multiprocessing2.py ├── day6 ├── 25_python_itertools.ipynb ├── _hello_cpp.so ├── add.c ├── coroutine.ipynb ├── function caching.ipynb ├── hello_cpp.cpp ├── hello_cpp.h ├── hello_cpp.i ├── hello_cpp.o ├── hello_cpp.py ├── hello_cpp_wrap.cxx ├── hello_cpp_wrap.o ├── img │ └── Capture.PNG ├── numpy_심화.ipynb └── python_c_extension.ipynb └── day7 ├── CustomLogger.py ├── One_liners_and_underscores.ipynb ├── class.ipynb ├── context_manager.ipynb ├── demo.txt ├── design patterns.ipynb ├── my_functions.py ├── my_script.py ├── one_liners_csv_file.csv ├── pip_package_manager.ipynb └── py_compatibility.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf 17 | 18 | .ipynb_checkpoints 19 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 데이터뽀개기 중급 파이썬 스터디 발표자료 2 | 3 | - [스터디 소개](http://databreak.org/activity/12/) 4 | - [스터디 커리큘럼 구글시트](https://tinyurl.com/interpykr) 5 | - [주교재: Intermediate python 한국어판 깃북](https://ddanggle.gitbooks.io/interpy-kr/content/) 6 | - [부교재: 파이썬 - 기본을 갈고 닦자!](https://wikidocs.net/book/1553) 7 | 8 | 9 | ## 스터디 자료 10 | |요일 |주제 |발표자 |발표자료 |비고| 11 | |---|---|---|---|---| 12 | |2019.04.13(토)|args와 kwargs|홍수린|[발표자료](https://nbviewer.jupyter.org/github/KaggleBreak/interpy-kr/blob/master/day1/1_args.ipynb)|| 13 | ||first class function|홍수린|[발표자료](https://nbviewer.jupyter.org/github/KaggleBreak/interpy-kr/blob/master/day1/2_firstclass_function.ipynb)| 14 | |2019.04.27(토)|데코레이터|홍수린|[발표자료](https://nbviewer.jupyter.org/github/KaggleBreak/interpy-kr/blob/master/day2/3_decorator.ipynb)|| 15 | ||제너레이터|정한웅|[발표자료](https://nbviewer.jupyter.org/github/KaggleBreak/interpy-kr/blob/master/day2/4_Generator.ipynb)| 16 | ||set자료구조|천성필|[발표자료](https://nbviewer.jupyter.org/github/KaggleBreak/interpy-kr/blob/master/day2/5_set.ipynb)| 17 | ||변형(Mutation)|유동건|[발표자료](https://nbviewer.jupyter.org/github/KaggleBreak/interpy-kr/blob/master/day2/6_mutation.ipynb)| 18 | ||객체 탐구|박원상|[발표자료]()| 19 | ||전역변수 & 반환|박원상|[발표자료](https://nbviewer.jupyter.org/github/KaggleBreak/interpy-kr/blob/master/day2/8_scope/8_scope.ipynb)| 20 | |2019.05.11(토)|삼항연산자|홍만수|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day3/09_ternary_op.ipynb)|| 21 | ||람다|이상열|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day3/10_lambda_functions.ipynb)| 22 | ||컴프리헨션(comprehension)|김지미|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day3/11_Comprehension.ipynb)| 23 | ||For-else|김지미|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day3/12_For-else.ipynb)| 24 | ||콜렉션(collections)|정한웅|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day3/13_collections.ipynb)| 25 | ||__slots__ 마법|유동건|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day3/14___slots__.ipynb)| 26 | |2019.05.25(토)|파이썬에서의 garbage collection(gc)|유동건|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day4/garbage%20collection.ipynb)|| 27 | ||디버깅|김민혁|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day4/15_debugging.ipynb)| 28 | ||unittest|김민혁|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day4/15_unittest.ipynb)| 29 | ||가상환경|김민혁|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day4/16_virtualenv.ipynb)| 30 | ||열거(enumerate)|정한웅|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day3/13_enumerate.ipynb)| 31 | ||logging|황원택|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day4/17_logging.ipynb)| 32 | ||profiling|홍수린|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day4/Profiling.ipynb)| 33 | |2019.06.08(토)|예외처리|천성필|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day4/Exception.ipynb)|| 34 | ||open 함수|황원택|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day5/22_open.ipynb)| 35 | ||map & reduce & filter함수|이상열|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day5/map_reduce_filter.ipynb)| 36 | ||multiprocessing|홍수린|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day5/multiprocessing.ipynb)| 37 | |2019.06.22(토)|numpy 심화|김지미|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day6/numpy_%E1%84%89%E1%85%B5%E1%86%B7%E1%84%92%E1%85%AA.ipynb)|| 38 | ||python C 확장|홍수린|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day6/python_c_extension.ipynb)| 39 | ||코루틴(yield)|정한웅|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day6/coroutine.ipynb)| 40 | ||함수 캐싱|김민혁|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day6/function%20caching.ipynb)| 41 | ||itertools|황원택|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day6/25_python_itertools.ipynb)| 42 | |2019.07.06(토)|컨텍스트 매니저(context manager)|이상열|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day7/context_manager.ipynb)|| 43 | ||class 심화|김민혁|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day7/class.ipynb)| 44 | ||한줄 명령어(oneLiners)|황원택|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day7/One_liners_and_underscores.ipynb)| 45 | ||파이썬 2+3 호환|홍만수|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day7/py_compatibility.ipynb)| 46 | ||pip 패키지 매니저|천성필|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day7/pip_package_manager.ipynb)| 47 | ||파이썬 디자인 패턴|홍수린|[발표자료](https://github.com/KaggleBreak/interpy-kr/blob/master/day7/design%20patterns.ipynb)| 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /day1/1_args.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "collapsed": true 7 | }, 8 | "source": [ 9 | "# 1. \\*args와 **kwargs" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "- 파이썬은 타 언어에 비해 비교적 연산자 및 연산의 종류가 풍부한 편이다.\n", 17 | "- 특히 파이썬이 지원하는 많은 연산자중 하나인 Asterisk(*)는 단순히 곱셈 이상의 여러 의미를 갖는 연산들을 가능케한다.\n", 18 | "\n", 19 | "- 파이썬에서 Asterisk(*)는 다음과 같은 상황에서 사용되는데 크게 4가지의 경우가 있다.\n", 20 | " - 곱셈 및 거듭제곱 연산으로 사용할 때\n", 21 | " - 리스트형 컨테이너 타입의 데이터를 반복 확장하고자 할 때\n", 22 | " - 가변인자 (Variadic Arguments)를 사용하고자 할 때\n", 23 | " - 컨테이너 타입의 데이터를 Unpacking 할 때" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "## 1. 곱셈 및 거듭제곱 연산으로 사용, 리스트형 컨테이너 타입의 데이터를 반복 확장" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 2, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "data": { 40 | "text/plain": [ 41 | "6" 42 | ] 43 | }, 44 | "execution_count": 2, 45 | "metadata": {}, 46 | "output_type": "execute_result" 47 | } 48 | ], 49 | "source": [ 50 | "2 * 3" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 3, 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "data": { 60 | "text/plain": [ 61 | "8" 62 | ] 63 | }, 64 | "execution_count": 3, 65 | "metadata": {}, 66 | "output_type": "execute_result" 67 | } 68 | ], 69 | "source": [ 70 | "2 ** 3" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 6, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "# 길이 100의 제로값 리스트 초기화\n", 80 | "zeros_list = [0] * 100" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 7, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "# 길이 100의 제로값 튜플 선언\n", 90 | "zeros_tuple = (0,) * 100" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "## 2. 가변인자 (Variadic Parameters)를 사용하고자 할 때" 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "- 우리는 종종 어떤 함수에서 가변인자를 필요로 할 때가 있다. 예를 들어, 들어오는 인자의 갯수를 모른다거나, 그 어떤 인자라도 모두 받아서 처리를 해야하는때가 있다.\n", 105 | "- 파이썬에서는 인자의 종류가 2가지가 있는데 하나는 positional arguments이고, 하나는 keyword arguments이다. 전자는 말그대로 위치에 따라 정해지는 인자이며, 후자는 키워드를 가진 즉, 이름을 가진 인자를 말한다.\n", 106 | "- variadic positional/keyword arguments를 살펴보기 전에 간단하게 positional arguments과 keyword arguments에 대해 살펴보겠다." 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 8, 112 | "metadata": {}, 113 | "outputs": [ 114 | { 115 | "name": "stdout", 116 | "output_type": "stream", 117 | "text": [ 118 | "{1: 'ming', 2: 'alice', 3: 'Nobody', 4: 'Nobody'}\n", 119 | "{1: 'alice', 2: 'ming', 3: 'mike', 4: 'Nobody'}\n", 120 | "{1: 'alice', 2: 'ming', 3: 'mike', 4: 'jim'}\n" 121 | ] 122 | } 123 | ], 124 | "source": [ 125 | "# 2~4명의 주자로 이루어진 달리기 대회 랭킹을 보여주는 함수\n", 126 | "def save_ranking(first, second, third=None, fourth=None):\n", 127 | " rank = {}\n", 128 | " rank[1], rank[2] = first, second\n", 129 | " rank[3] = third if third is not None else 'Nobody'\n", 130 | " rank[4] = fourth if fourth is not None else 'Nobody'\n", 131 | " print(rank)\n", 132 | "\n", 133 | "# positional arguments 2개 전달\n", 134 | "save_ranking('ming', 'alice')\n", 135 | "# positional arguments 2개와 keyword argument 1개 전달\n", 136 | "save_ranking('alice', 'ming', third='mike')\n", 137 | "# positional arguments 2개와 keyword arguments 2개 전달 (단, 하나는 positional argument 형태로 전달)\n", 138 | "save_ranking('alice', 'ming', 'mike', fourth='jim')" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "- 위의 함수는 first, second라는 두 개의 positional arguments를 받으며 third, fourth라는 두 개의 keyword arguments를 받고 있다\n", 146 | "- positional arguments의 경우 생략이 불가능하며 갯수대로 정해진 위치에 인자를 전달해야한다\n", 147 | "- 그러나 keyword arguments의 경우 함수 선언시 디폴트값을 설정할 수 있으며, 만약 인자를 생략할 시 해당 디폴트값이 인자의 값으로 들어간다. \n", 148 | "- 즉, 이 형태의 인자는 생략이 가능하다. 따라서, 여기서 알 수 있는건 keyword arguments의 경우 생략이 가능하기 때문에, positional arguments 이전에 선언될 수는 없다. 즉, 다음의 코드는 에러를 발생시킨다." 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "metadata": {}, 155 | "outputs": [], 156 | "source": [ 157 | "# 에러 발생\n", 158 | "def save_ranking(first, second=None, third, fourth=None):\n", 159 | " ..." 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": {}, 165 | "source": [ 166 | "- 세 번째를 보면 positional arguments가 3개, keyword argument가 1개 전달되고 있다. 눈치가 빠른 사람을 알겠지만, keyword arguments의 경우 선언된 위치만 동일할 경우 키워드를 제외하고 positional arguments 형태로 전달이 가능하다. \n", 167 | "- 즉, 위에서 mike는 자동적으로 third라는 키로 전달이 된다.\n", 168 | "- 여기까지가 파이썬의 arguments에 관한 기본적인 설명이다. 그런데, 여기서 한 가지 문제를 맞닥뜨릴 수 있다. 만약, 최대 4명의 주자가 아닌 10명 또는 그 이상의 정해지지 않은 주자가 있다고 해보자. 이 경우엔 10개의 인자를 선언하기도 번거로우며, 특히, 주자의 수가 미정일 경우 위와 같은 형태로는 처리가 불가능하다. \n", 169 | "- 이 때 사용하는게 바로 가변인자 (Variadic Arguments)이다. 가변인자는 좀 전에 위에서 설명한 positional arguments와 keyword arguments에 모두 사용할 수 있다" 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "metadata": {}, 175 | "source": [ 176 | "### positional arguments만 받을 때" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": 9, 182 | "metadata": {}, 183 | "outputs": [ 184 | { 185 | "name": "stdout", 186 | "output_type": "stream", 187 | "text": [ 188 | "('ming', 'alice', 'tom', 'wilson', 'roy')\n" 189 | ] 190 | } 191 | ], 192 | "source": [ 193 | "def save_ranking(*args):\n", 194 | " print(args)\n", 195 | "save_ranking('ming', 'alice', 'tom', 'wilson', 'roy')\n", 196 | "# ('ming', 'alice', 'tom', 'wilson', 'roy')" 197 | ] 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "metadata": {}, 202 | "source": [ 203 | "### keyword arguments만 받을 때" 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": 10, 209 | "metadata": {}, 210 | "outputs": [ 211 | { 212 | "name": "stdout", 213 | "output_type": "stream", 214 | "text": [ 215 | "{'second': 'alice', 'fourth': 'wilson', 'fifth': 'roy', 'third': 'tom', 'first': 'ming'}\n" 216 | ] 217 | } 218 | ], 219 | "source": [ 220 | "def save_ranking(**kwargs):\n", 221 | " print(kwargs)\n", 222 | "save_ranking(first='ming', second='alice', fourth='wilson', third='tom', fifth='roy')\n", 223 | "# {'first': 'ming', 'second': 'alice', 'fourth': 'wilson', 'third': 'tom', 'fifth': 'roy'}" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": {}, 229 | "source": [ 230 | "### positional arguments와 keyword arguments를 모두 받을 때" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 11, 236 | "metadata": {}, 237 | "outputs": [ 238 | { 239 | "name": "stdout", 240 | "output_type": "stream", 241 | "text": [ 242 | "('ming', 'alice', 'tom')\n", 243 | "{'fourth': 'wilson', 'fifth': 'roy'}\n" 244 | ] 245 | } 246 | ], 247 | "source": [ 248 | "def save_ranking(*args, **kwargs):\n", 249 | " print(args)\n", 250 | " print(kwargs)\n", 251 | "save_ranking('ming', 'alice', 'tom', fourth='wilson', fifth='roy')\n", 252 | "# ('ming', 'alice', 'tom')\n", 253 | "# {'fourth': 'wilson', 'fifth': 'roy'}" 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": {}, 259 | "source": [ 260 | "- 위에서 *args는 임의의 갯수의 positional arguments를 받음을 의미하며, **kwargs는 임의의 갯수의 keyword arguments를 받음을 의미한다. 이 때 *args, **kwargs 형태로 가변인자를 받는걸 packing이라고 한다.\n", 261 | "- 위의 예시에서 볼 수 있듯이, 임의의 갯수와 임의의 키값을 갖는 인자들을 전달하고 있다. positional 형태로 전달되는 인자들은 args라는 tuple에 저장되며, keyword 형태로 전달되는 인자들은 kwargs라는 dict에 저장된다.\n", 262 | "- 아까 positional과 keyword의 선언 순서를 언급했었는데, keyword는 positional보다 앞에 선언할 수 없기 때문에 다음의 코드는 에러를 발생시킨다." 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": null, 268 | "metadata": {}, 269 | "outputs": [], 270 | "source": [ 271 | "# 에러 발생\n", 272 | "def save_ranking(**kwargs, *args):\n", 273 | " ..." 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "- 이 가변인자는 매우 일반적으로 사용되는 기능으로 많은 오픈소스 코드에서도 쉽게 찾아볼 수 있다.\n", 281 | "- 보통 오픈소스의 경우 코드의 일관성을 위해 *args이나 **kwargs와 같이 관례적으로 사용되는 인자명을 사용하지만, *required나 **optional과 같이 인자명은 일반 변수와 같이 원하는대로 지정이 가능하다. \n", 282 | "- 단, 만약 오픈소스 프로젝트를 하고 있고, 인자에 특별한 의미가 있지 않은 일반적인 가변인자라면 *args와 **kwargs와 같이 관례를 따르는게 좋다." 283 | ] 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "metadata": {}, 288 | "source": [ 289 | "## 3. 컨테이너 타입의 데이터를 Unpacking 할 때" 290 | ] 291 | }, 292 | { 293 | "cell_type": "markdown", 294 | "metadata": {}, 295 | "source": [ 296 | "- \\*는 컨테이너 타입의 데이터를 unpacking 하는 경우에도 사용될 수 있다. 이는 3번과 유사한 원리로, 종종 사용할만한 기능(연산)이다. 가장 쉬운 예로, 다음과 같이 우리가 *list*나 tuple 또는 dict 형태의 데이터를 가지고 있고 어떤 함수가 가변인자를 받는 경우에 사용할 수 있다." 297 | ] 298 | }, 299 | { 300 | "cell_type": "code", 301 | "execution_count": 12, 302 | "metadata": {}, 303 | "outputs": [ 304 | { 305 | "data": { 306 | "text/plain": [ 307 | "[2, 3, 5, 7, 11, 13]" 308 | ] 309 | }, 310 | "execution_count": 12, 311 | "metadata": {}, 312 | "output_type": "execute_result" 313 | } 314 | ], 315 | "source": [ 316 | "from functools import reduce\n", 317 | "\n", 318 | "primes = [2, 3, 5, 7, 11, 13]\n", 319 | "\n", 320 | "def product(*numbers):\n", 321 | " p = reduce(lambda x, y: x * y, numbers)\n", 322 | " return p\n", 323 | "\n", 324 | "product(*primes)\n", 325 | "# 30030\n", 326 | "\n", 327 | "product(primes)\n", 328 | "# [2, 3, 5, 7, 11, 13]" 329 | ] 330 | }, 331 | { 332 | "cell_type": "markdown", 333 | "metadata": {}, 334 | "source": [ 335 | "- `product()` 함수가 가변인자를 받고 있기 때문에 우리는 리스트의 데이터를 모두 unpacking하여 함수에 전달해야한다. \n", 336 | "- 이 경우 함수에 값을 전달할 때 *primes와 같이 전달하면 primes 리스트의 모든 값들이 unpacking되어 numbers라는 리스트에 저장된다. \n", 337 | "- 만약 이를 primes 그대로 전달한다면 이 자체가 하나의 값으로 쓰여 numbers에는 primes라는 원소가 하나 존재하게 된다.\n", 338 | "\n", 339 | "- \\*tuple*도 *list*와 정확히 동일하게 동작하며 *dict*의 경우 * 대신 **을 사용하여 동일한 형태로 사용할 수 있다." 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 13, 345 | "metadata": {}, 346 | "outputs": [ 347 | { 348 | "name": "stdout", 349 | "output_type": "stream", 350 | "text": [ 351 | "content length: 348\n" 352 | ] 353 | }, 354 | { 355 | "ename": "ValueError", 356 | "evalue": "You must use SSL for http communication", 357 | "output_type": "error", 358 | "traceback": [ 359 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 360 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 361 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'You must use SSL for http communication'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0mpre_process\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0;31m# content length: 348\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;31m# Traceback (most recent call last):\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 362 | "\u001b[0;32m\u001b[0m in \u001b[0;36mpre_process\u001b[0;34m(**headers)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mhost\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mheaders\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'Host'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;34m'https'\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mhost\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'You must use SSL for http communication'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mpre_process\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mheaders\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 363 | "\u001b[0;31mValueError\u001b[0m: You must use SSL for http communication" 364 | ] 365 | } 366 | ], 367 | "source": [ 368 | "headers = {\n", 369 | " 'Accept': 'text/plain',\n", 370 | " 'Content-Length': 348,\n", 371 | " 'Host': 'http://mingrammer.com'\n", 372 | "}\n", 373 | "\n", 374 | "def pre_process(**headers):\n", 375 | " content_length = headers['Content-Length']\n", 376 | " print('content length: ', content_length)\n", 377 | "\n", 378 | " host = headers['Host']\n", 379 | " if 'https' not in host:\n", 380 | " raise ValueError('You must use SSL for http communication')\n", 381 | "\n", 382 | "pre_process(**headers)\n", 383 | "# content length: 348\n", 384 | "# Traceback (most recent call last):\n", 385 | "# File \"\", line 1, in \n", 386 | "# File \"\", line 7, in pre_process\n", 387 | "# ValueError: You must use SSL for http communication" 388 | ] 389 | }, 390 | { 391 | "cell_type": "markdown", 392 | "metadata": {}, 393 | "source": [ 394 | "- 또 다른 형태의 unpacking이 한 가지 더 존재하는데, 이는 함수의 인자로써 사용하는게 아닌 리스트나 튜플 데이터를 다른 변수에 가변적으로 unpacking 하여 사용하는 형태이다." 395 | ] 396 | }, 397 | { 398 | "cell_type": "code", 399 | "execution_count": 14, 400 | "metadata": {}, 401 | "outputs": [], 402 | "source": [ 403 | "numbers = [1, 2, 3, 4, 5, 6]\n", 404 | "\n", 405 | "# unpacking의 좌변은 리스트 또는 튜플의 형태를 가져야하므로 단일 unpacking의 경우 *a가 아닌 *a,를 사용\n", 406 | "*a, = numbers\n", 407 | "# a = [1, 2, 3, 4, 5, 6]\n", 408 | "\n", 409 | "*a, b = numbers\n", 410 | "# a = [1, 2, 3, 4, 5]\n", 411 | "# b = 6\n", 412 | "\n", 413 | "a, *b, = numbers\n", 414 | "# a = 1\n", 415 | "# b = [2, 3, 4, 5, 6]\n", 416 | "\n", 417 | "a, *b, c = numbers\n", 418 | "# a = 1\n", 419 | "# b = [2, 3, 4, 5]\n", 420 | "# c = 6" 421 | ] 422 | }, 423 | { 424 | "cell_type": "markdown", 425 | "metadata": {}, 426 | "source": [ 427 | "- 여기서 \\*a, *b로 받는 부분들은 우변의 리스트 또는 튜플이 unpacking된 후, 다른 변수들에 할당된 값 외의 나머지 값들을 다시 하나의 리스트로 packing한다. 이는 3번에서 살펴본 가변인자 packing과 동일한 개념이다." 428 | ] 429 | }, 430 | { 431 | "cell_type": "markdown", 432 | "metadata": {}, 433 | "source": [ 434 | "- 참고문헌\n", 435 | " - https://mingrammer.com/understanding-the-asterisk-of-python/" 436 | ] 437 | } 438 | ], 439 | "metadata": { 440 | "kernelspec": { 441 | "display_name": "Python 2", 442 | "language": "python", 443 | "name": "python2" 444 | }, 445 | "language_info": { 446 | "codemirror_mode": { 447 | "name": "ipython", 448 | "version": 3 449 | }, 450 | "file_extension": ".py", 451 | "mimetype": "text/x-python", 452 | "name": "python", 453 | "nbconvert_exporter": "python", 454 | "pygments_lexer": "ipython3", 455 | "version": "3.5.2" 456 | } 457 | }, 458 | "nbformat": 4, 459 | "nbformat_minor": 1 460 | } 461 | -------------------------------------------------------------------------------- /day1/2_firstclass_function.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 2. Firstclass function" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "## 퍼스트클래스 함수 & 클로저\n", 15 | "- 퍼스트클래스 함수란 프로그래밍 언어가 함수 (function) 를 first-class citizen으로 취급하는 것을 뜻합니다. 쉽게 설명하자면 함수 자체를 인자 (argument) 로써 다른 함수에 전달하거나 다른 함수의 결과값으로 리턴 할수도 있고, 함수를 변수에 할당하거나 데이터 구조안에 저장할 수 있는 함수를 뜻합니다." 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 2, 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "name": "stdout", 25 | "output_type": "stream", 26 | "text": [ 27 | "25\n", 28 | "\n", 29 | "\n" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "def square(x):\n", 35 | " return x * x\n", 36 | "\n", 37 | "print(square(5))\n", 38 | "\n", 39 | "f = square\n", 40 | "\n", 41 | "print(square)\n", 42 | "print(f)" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "- 위의 코드를 보면 아주 간단한 함수 \"square\"를 정의하고 호출하였습니다. 그 다음에 square 함수를 \"f\"라는 변수에 할당한 후에 square와 f의 값을 출력해 보았습니다. \n", 50 | "- 둘다 메모리 주소값인 0x1018dfe60에 저장된 square 함수 오브젝트가 할당되어 있는 것을 볼 수 있습니다. 그럼 f도 진짜 함수처럼 호출을할 수 있는지 볼까요." 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 4, 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "name": "stdout", 60 | "output_type": "stream", 61 | "text": [ 62 | "25\n" 63 | ] 64 | } 65 | ], 66 | "source": [ 67 | "def square(x):\n", 68 | " return x * x\n", 69 | "\n", 70 | "f = square\n", 71 | "\n", 72 | "print(f(5))" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "- f(5) 구문으로 square 함수를 호출한 것을 볼 수 있습니다. \n", 80 | "- 위에서 언급했듯이 프로그래밍 언어가 퍼스트클래스 함수를 지원하면, 금방 해본 것처럼 변수에 함수를 할당할 수 있을뿐만 아니라, 인자로써 다른 함수에 전달하거나, 함수의 리턴값으로도 사용할 수가 있습니다. " 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 5, 86 | "metadata": {}, 87 | "outputs": [ 88 | { 89 | "name": "stdout", 90 | "output_type": "stream", 91 | "text": [ 92 | "[1, 4, 9, 16, 25]\n" 93 | ] 94 | } 95 | ], 96 | "source": [ 97 | "def square(x):\n", 98 | " return x * x\n", 99 | "\n", 100 | "def my_map(func, arg_list):\n", 101 | " result = []\n", 102 | " for i in arg_list:\n", 103 | " result.append(func(i)) # square 함수 호출, func == square\n", 104 | " return result\n", 105 | "\n", 106 | "num_list = [1, 2, 3, 4, 5]\n", 107 | "\n", 108 | "squares = my_map(square, num_list)\n", 109 | "\n", 110 | "print(squares)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "- my_map 함수에 square 함수를 인자로 전달한 후 for 루프안에서 square 함수를 호출한 것을 볼 수 있습니다. 그런데 밑에와 같이 simple_sqaure 함수 하나로 문제를 해결하면 되지 않냐고 생각하시는 분들이 있으실 겁니다. " 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 6, 123 | "metadata": {}, 124 | "outputs": [ 125 | { 126 | "name": "stdout", 127 | "output_type": "stream", 128 | "text": [ 129 | "[1, 4, 9, 16, 25]\n" 130 | ] 131 | } 132 | ], 133 | "source": [ 134 | "def square(x):\n", 135 | " return x * x\n", 136 | "\n", 137 | "num_list = [1, 2, 3, 4, 5]\n", 138 | "\n", 139 | "def simple_square(arg_list):\n", 140 | " result = []\n", 141 | " for i in arg_list:\n", 142 | " result.append(i * i)\n", 143 | " return result\n", 144 | "\n", 145 | "simple_squares = simple_square(num_list)\n", 146 | "\n", 147 | "print(simple_squares)" 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": {}, 153 | "source": [ 154 | "- 더 간단한 코드로 같은 결과가 나왔습니다\n", 155 | "- 간단히 함수 하나만을 실행하고 싶을때는 simple_square와 같은 일반 함수를 사용하여 같은 결과를 낼 수도 있습니다. 하지만, 퍼스트클래스 함수를 사용하면 이미 정의된 여러 함수를 간단히 재활용할 수 있다는 장점이 있습니다. " 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 7, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "name": "stdout", 165 | "output_type": "stream", 166 | "text": [ 167 | "[1, 4, 9, 16, 25]\n", 168 | "[1, 8, 27, 64, 125]\n", 169 | "[1, 16, 81, 256, 625]\n" 170 | ] 171 | } 172 | ], 173 | "source": [ 174 | "def square(x):\n", 175 | " return x * x\n", 176 | "\n", 177 | "def cube(x):\n", 178 | " return x * x * x\n", 179 | "\n", 180 | "def quad(x):\n", 181 | " return x * x * x * x\n", 182 | "\n", 183 | "def my_map(func, arg_list):\n", 184 | " result = []\n", 185 | " for i in arg_list:\n", 186 | " result.append(func(i)) # square 함수 호출, func == square\n", 187 | " return result\n", 188 | "\n", 189 | "num_list = [1, 2, 3, 4, 5]\n", 190 | "\n", 191 | "squares = my_map(square, num_list)\n", 192 | "cubes = my_map(cube, num_list)\n", 193 | "quads = my_map(quad, num_list)\n", 194 | "\n", 195 | "print(squares)\n", 196 | "print(cubes)\n", 197 | "print(quads)" 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "metadata": {}, 203 | "source": [ 204 | "- 위의 예제와 같이 이미 정의되어 있는 함수 square, cube, quad와 같은 여러개의 함수나 모듈이 있다고 가정했을때 my_map과 같은 wrapper 함수를 하나만 정의하여 기존의 함수나 모듈을 수정할 필요없이 편리하게 쓸 수가 있는겁니다.\n", 205 | "- 이번에는 함수의 결과값으로 또 다른 함수를 리턴하는 방법을 살펴보겠습니다. 아주 간단한 로깅 함수를 만들어 보겠습니다." 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 9, 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "name": "stdout", 215 | "output_type": "stream", 216 | "text": [ 217 | ".log_message at 0x7f99fc616510>\n", 218 | "Log: Hi\n" 219 | ] 220 | } 221 | ], 222 | "source": [ 223 | "def logger(msg):\n", 224 | " def log_message(): #1\n", 225 | " print('Log: ' + msg)\n", 226 | " return log_message\n", 227 | "\n", 228 | "log_hi = logger('Hi')\n", 229 | "print(log_hi) # log_message 오브젝트가 출력됩니다.\n", 230 | "log_hi() # \"Log: Hi\"가 출력됩니다." 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": {}, 236 | "source": [ 237 | "- 위의 #1에서 정의된 log_message라는 함수를 logger 함수의 리턴값으로 리턴하여 log_hi라는 변수에 할당한 후 호출한 것을 볼 수 있습니다.\n", 238 | "- 그런데 여기서 특이한 점을 볼 수 있습니다. msg와 같은 함수의 지역변수값은 함수가 호출된 이후에 메모리상에서 사라지므로 다시 참조할 수가 없는데, msg 변수에 할당됐던 'Hi'값이 logger 함수가 종료된 이후에도 참조 됐다는 것입니다. \n", 239 | "- 이런 log_message와 같은 함수를 \"클로저 (closure)\"라고 부르며 클로저는 다른 함수의 지역변수를 그 함수가 종료된 이후에도 기억을 할 수가 있습니다. \n", 240 | "- log_message가 정말 기억을 하고 있는지 msg 변수를 지역변수로 가지고 있는 logger 함수를 글로벌 네임스페이스에서 완전히 지운 후, log_message를 호출하여 보겠습니다." 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": 10, 246 | "metadata": {}, 247 | "outputs": [ 248 | { 249 | "name": "stdout", 250 | "output_type": "stream", 251 | "text": [ 252 | ".log_message at 0x7f99fc616158>\n", 253 | "Log: Hi\n", 254 | "NameError: logger는 존재하지 않습니다.\n", 255 | "Log: Hi\n" 256 | ] 257 | } 258 | ], 259 | "source": [ 260 | "def logger(msg):\n", 261 | " \n", 262 | " def log_message(): #1\n", 263 | " print('Log: ' + msg)\n", 264 | " \n", 265 | " return log_message\n", 266 | "\n", 267 | "log_hi = logger('Hi')\n", 268 | "print(log_hi) # log_message 오브젝트가 출력됩니다.\n", 269 | "log_hi() # \"Log: Hi\"가 출력됩니다.\n", 270 | "\n", 271 | "del logger # 글로벌 네임스페이스에서 logger 오브젝트를 지웁니다.\n", 272 | "\n", 273 | "# logger 오브젝트가 지워진 것을 확인합니다.\n", 274 | "try:\n", 275 | " print(logger)\n", 276 | "except NameError:\n", 277 | " print('NameError: logger는 존재하지 않습니다.')\n", 278 | "\n", 279 | "log_hi() # logger가 지워진 뒤에도 Log: Hi\"가 출력됩니다." 280 | ] 281 | }, 282 | { 283 | "cell_type": "markdown", 284 | "metadata": {}, 285 | "source": [ 286 | "- logger가 지워진 뒤에도 log_hi()를 실행하여 log_message가 호출된 것을 볼 수 있습니다.\n", 287 | "- logger 함수를 완전히 삭제한 이후에도 log_message 함수는 'Hi'를 기억하고 있는 것을 확인했습니다. 이런식으로 closure는 여러가지로 편리하게 쓰여질 때가 많습니다" 288 | ] 289 | }, 290 | { 291 | "cell_type": "markdown", 292 | "metadata": {}, 293 | "source": [ 294 | "- 참고문헌\n", 295 | " - http://schoolofweb.net/blog/posts/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%8D%BC%EC%8A%A4%ED%8A%B8%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%95%A8%EC%88%98-first-class-function/\n", 296 | " - https://medium.com/@lazysoul/functional-programming-%EC%97%90%EC%84%9C-1%EA%B8%89-%EA%B0%9D%EC%B2%B4%EB%9E%80-ba1aeb048059\n", 297 | " - https://nachwon.github.io/closure/" 298 | ] 299 | } 300 | ], 301 | "metadata": { 302 | "kernelspec": { 303 | "display_name": "data", 304 | "language": "python", 305 | "name": "data" 306 | }, 307 | "language_info": { 308 | "codemirror_mode": { 309 | "name": "ipython", 310 | "version": 3 311 | }, 312 | "file_extension": ".py", 313 | "mimetype": "text/x-python", 314 | "name": "python", 315 | "nbconvert_exporter": "python", 316 | "pygments_lexer": "ipython3", 317 | "version": "3.5.2" 318 | } 319 | }, 320 | "nbformat": 4, 321 | "nbformat_minor": 2 322 | } 323 | -------------------------------------------------------------------------------- /day2/.ipynb_checkpoints/mutation-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 9. 변형 (Mutation)\n", 8 | "참고자료\n", 9 | " - https://medium.com/@meghamohan/mutable-and-immutable-side-of-python-c2145cf72747\n", 10 | " - https://medium.com/@birnbera/objects-memory-and-mutation-in-python-810bf090b63c" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "## Python 기본 자료형의 변형 가능 여부" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "| Class | Mutable |\n", 25 | "|:---:|:---:|\n", 26 | "| bool | X |\n", 27 | "| int | X |\n", 28 | "| float | X |\n", 29 | "| list | O |\n", 30 | "| tuple | X |\n", 31 | "| str | X |\n", 32 | "| set | O |\n", 33 | "| frozenset | X |\n", 34 | "| dict | O |" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "## 예시\n", 42 | "### List" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 1, 48 | "metadata": {}, 49 | "outputs": [ 50 | { 51 | "name": "stdout", 52 | "output_type": "stream", 53 | "text": [ 54 | "['hi']\n" 55 | ] 56 | } 57 | ], 58 | "source": [ 59 | "foo = ['hi']\n", 60 | "print(foo) # ['hi']" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "bar에 'bye'를 추가했지만 bar와 foo가 동일한 주소를 참조하고 있어 foo의 참조 값도 같이 변경" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 2, 73 | "metadata": {}, 74 | "outputs": [ 75 | { 76 | "name": "stdout", 77 | "output_type": "stream", 78 | "text": [ 79 | "['hi', 'bye']\n" 80 | ] 81 | } 82 | ], 83 | "source": [ 84 | "bar = foo\n", 85 | "bar += ['bye']\n", 86 | "print(foo) # ['hi', 'bye']" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 3, 92 | "metadata": {}, 93 | "outputs": [ 94 | { 95 | "name": "stdout", 96 | "output_type": "stream", 97 | "text": [ 98 | "0x24a5d352fc8 \n", 99 | "0x24a5d352fc8 \n", 100 | "True\n" 101 | ] 102 | } 103 | ], 104 | "source": [ 105 | "print(hex(id(foo)), type(foo)) # 0x24a5d352fc8 \n", 106 | "print(hex(id(bar)), type(bar)) # 0x24a5d352fc8 \n", 107 | "print(foo == bar) # True" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "### Integer\n", 115 | "int도 유사하지만 약간의 차이가 있다\n", 116 | "\n", 117 | "예시) 10이라는 정수 자체가 이미 메모리에 할당돼 있어 x는 해당 주소를 참조하는 형태" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 4, 123 | "metadata": {}, 124 | "outputs": [ 125 | { 126 | "name": "stdout", 127 | "output_type": "stream", 128 | "text": [ 129 | "True\n", 130 | "True\n", 131 | "True\n", 132 | "0x7459b200\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "x = 10\n", 138 | "y = x\n", 139 | "\n", 140 | "print(id(x) == id(y)) # True\n", 141 | "print(id(x) == id(10)) # True\n", 142 | "print(id(y) == id(10)) # True\n", 143 | "print(hex(id(10))) # 0x7459b200" 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": {}, 149 | "source": [ 150 | "따라서 x += 1을 해줄 경우 x의 주소가 변하는 것처럼 결과가 나오는데 이는 사실 x가 11을 참조하기 때문" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 5, 156 | "metadata": {}, 157 | "outputs": [ 158 | { 159 | "name": "stdout", 160 | "output_type": "stream", 161 | "text": [ 162 | "False\n", 163 | "True\n", 164 | "True\n", 165 | "0x7459b200\n", 166 | "0x7459b220\n" 167 | ] 168 | } 169 | ], 170 | "source": [ 171 | "x += 1\n", 172 | "\n", 173 | "print(id(x) == id(y)) # False\n", 174 | "print(id(x) == id(11)) # True\n", 175 | "print(id(y) == id(10)) # True\n", 176 | "print(hex(id(10))) # 0x7459b200\n", 177 | "print(hex(id(11))) # 0x7459b220" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 6, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "name": "stdout", 187 | "output_type": "stream", 188 | "text": [ 189 | "True\n", 190 | "True\n", 191 | "0x7459b220\n" 192 | ] 193 | } 194 | ], 195 | "source": [ 196 | "y += 1\n", 197 | "\n", 198 | "print(id(x) == id(y)) # True\n", 199 | "print(id(x) == id(11)) # True\n", 200 | "print(hex(id(11))) # 0x7459b220" 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": {}, 206 | "source": [ 207 | "### Tuple은 과연 불변할까?\n", 208 | "Tuple은 파이썬의 대표적인 불변 자료형인데 Tuple의 요소는 충분히 변형 가능하다" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 7, 214 | "metadata": {}, 215 | "outputs": [ 216 | { 217 | "name": "stdout", 218 | "output_type": "stream", 219 | "text": [ 220 | "('holberton', [1, 2, 3])\n", 221 | "False\n" 222 | ] 223 | } 224 | ], 225 | "source": [ 226 | "s = ('holberton', [1, 2, 3])\n", 227 | "t = s\n", 228 | "s += (5,)\n", 229 | "print(t) # ('holberton', [1, 2, 3])\n", 230 | "print(id(s) == id(t)) # False" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 8, 236 | "metadata": {}, 237 | "outputs": [ 238 | { 239 | "ename": "TypeError", 240 | "evalue": "'tuple' object does not support item assignment", 241 | "output_type": "error", 242 | "traceback": [ 243 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 244 | "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", 245 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0ms\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;31m# Error\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 246 | "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" 247 | ] 248 | } 249 | ], 250 | "source": [ 251 | "s[1] += [5,] # Error" 252 | ] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "metadata": {}, 257 | "source": [ 258 | "하지만 실제 s\\[1\\]이 참조하고 있는 list에는 새 요소가 추가됐으며 t도 동일한 주소를 참조하고 있기 때문에 t에도 반영" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": 9, 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "name": "stdout", 268 | "output_type": "stream", 269 | "text": [ 270 | "('holberton', [1, 2, 3, 5], 5)\n", 271 | "('holberton', [1, 2, 3, 5])\n", 272 | "0x24a5cf51e48\n", 273 | "False\n" 274 | ] 275 | } 276 | ], 277 | "source": [ 278 | "print(s) # ('holberton', [1, 2, 3, 5], 5)\n", 279 | "print(t) # ('holberton', [1, 2, 3, 5])\n", 280 | "print(hex(id(s[1]))) # 0x24a5cf51e48\n", 281 | "print(id(s) == id(t)) # False" 282 | ] 283 | }, 284 | { 285 | "cell_type": "markdown", 286 | "metadata": {}, 287 | "source": [ 288 | "### 참조에 의한 호출\n", 289 | "참조(변형 가능한) 객체를 함수의 인자로 넘기기 때문에 실제로 함수 내에서 이뤄진 연산이 해당 객체에 반영" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": 10, 295 | "metadata": {}, 296 | "outputs": [ 297 | { 298 | "name": "stdout", 299 | "output_type": "stream", 300 | "text": [ 301 | "0x24a5d4094c8\n", 302 | "[5, 6, 10]\n", 303 | "0x24a5d4094c8\n" 304 | ] 305 | } 306 | ], 307 | "source": [ 308 | "def updateList(list1):\n", 309 | " list1 += [10]\n", 310 | "\n", 311 | "n = [5, 6]\n", 312 | "print(hex(id(n))) # 0x24a5d4094c8\n", 313 | "updateList(n)\n", 314 | "print(n) # [5, 6, 10]\n", 315 | "print(hex(id(n))) # 0x24a5d4094c8" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "### 값에 의한 호출\n", 323 | "하지만 아래와 같은 경우 객체가 참조하고 있는 값만을 넘겨주기 때문에 해당 함수를 호출하는 동안에만 참조 객체가 변경" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": 11, 329 | "metadata": {}, 330 | "outputs": [ 331 | { 332 | "name": "stdout", 333 | "output_type": "stream", 334 | "text": [ 335 | "0x7459b160\n", 336 | "0x7459b160 15 0x7459b2a0\n", 337 | "5\n" 338 | ] 339 | } 340 | ], 341 | "source": [ 342 | "def updateNumber(n):\n", 343 | " tmp = hex(id(n))\n", 344 | " n += 10\n", 345 | " print(tmp, n, hex(id(n)))\n", 346 | "\n", 347 | "b = 5\n", 348 | "updateNumber(b) # 0x7459b160 15 0x7459b2a0\n", 349 | "print(b) # 5" 350 | ] 351 | }, 352 | { 353 | "cell_type": "markdown", 354 | "metadata": {}, 355 | "source": [ 356 | "### 기타" 357 | ] 358 | }, 359 | { 360 | "cell_type": "markdown", 361 | "metadata": {}, 362 | "source": [ 363 | "257 이상의 숫자는 동적으로 메모리에 할당" 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": 23, 369 | "metadata": {}, 370 | "outputs": [ 371 | { 372 | "name": "stdout", 373 | "output_type": "stream", 374 | "text": [ 375 | "0x24a5d3fcfb0\n", 376 | "False\n", 377 | "False\n" 378 | ] 379 | } 380 | ], 381 | "source": [ 382 | "a = 257\n", 383 | "print(hex(id(a))) # 0x24a5d3fcfb0\n", 384 | "b = 257\n", 385 | "print(id(b) == id(a)) # False\n", 386 | "print(id(b) == id(257)) # False" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "정수는 32 byte C struct array에 저장" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": 24, 399 | "metadata": {}, 400 | "outputs": [ 401 | { 402 | "data": { 403 | "text/plain": [ 404 | "True" 405 | ] 406 | }, 407 | "execution_count": 24, 408 | "metadata": {}, 409 | "output_type": "execute_result" 410 | } 411 | ], 412 | "source": [ 413 | "id(10) - id(9) == id(9) - id(8) == id(8) - id(7) == 32 # True" 414 | ] 415 | }, 416 | { 417 | "cell_type": "code", 418 | "execution_count": 25, 419 | "metadata": {}, 420 | "outputs": [ 421 | { 422 | "data": { 423 | "text/plain": [ 424 | "True" 425 | ] 426 | }, 427 | "execution_count": 25, 428 | "metadata": {}, 429 | "output_type": "execute_result" 430 | } 431 | ], 432 | "source": [ 433 | "b = a\n", 434 | "id(b) == id(a) # True" 435 | ] 436 | }, 437 | { 438 | "cell_type": "markdown", 439 | "metadata": {}, 440 | "source": [ 441 | "하지만 257 이상의 숫자도 정수형이기 때문에 연산을 할 경우 새 객체를 생성" 442 | ] 443 | }, 444 | { 445 | "cell_type": "code", 446 | "execution_count": 26, 447 | "metadata": {}, 448 | "outputs": [ 449 | { 450 | "name": "stdout", 451 | "output_type": "stream", 452 | "text": [ 453 | "0x24a5d3fcfb0\n", 454 | "258 0x24a5d1ef470\n" 455 | ] 456 | } 457 | ], 458 | "source": [ 459 | "print(hex(id(b))) # 0x24a5d3fcfb0\n", 460 | "b += 1\n", 461 | "print(b, hex(id(b))) # 258 0x24a5d326ad0" 462 | ] 463 | }, 464 | { 465 | "cell_type": "markdown", 466 | "metadata": {}, 467 | "source": [ 468 | "동일하게 두 list의 요소를 추가하는 코드라도 inline 함수와 풀어서 쓰는 경우 차이가 있다" 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": 27, 474 | "metadata": {}, 475 | "outputs": [ 476 | { 477 | "name": "stdout", 478 | "output_type": "stream", 479 | "text": [ 480 | "0x24a5d46bbc8\n", 481 | "[1, 2, 1, 2] 0x24a5d46bd48\n", 482 | "[1, 2, 1, 2, 1, 2, 1, 2] 0x24a5d46bd48\n", 483 | "[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2] 0x24a5d46bd48\n" 484 | ] 485 | } 486 | ], 487 | "source": [ 488 | "a = [1, 2]\n", 489 | "print(hex(id(a))) # 0x24a5d46bbc8\n", 490 | "\n", 491 | "a = a + a\n", 492 | "print(a, hex(id(a))) # [1, 2, 1, 2] 0x24a5d46bd48\n", 493 | "\n", 494 | "a *= 2\n", 495 | "print(a, hex(id(a))) # [1, 2, 1, 2, 1, 2, 1, 2] 0x24a5d46bd48\n", 496 | "\n", 497 | "a += a\n", 498 | "print(a, hex(id(a))) # [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2] 0x24a5d46bd48" 499 | ] 500 | }, 501 | { 502 | "cell_type": "markdown", 503 | "metadata": {}, 504 | "source": [ 505 | "문자열의 경우도 특정 길이 이하의 문자열에 대해서는 정수와 동일한 방식으로 저장 및 참조" 506 | ] 507 | }, 508 | { 509 | "cell_type": "code", 510 | "execution_count": 16, 511 | "metadata": {}, 512 | "outputs": [ 513 | { 514 | "data": { 515 | "text/plain": [ 516 | "False" 517 | ] 518 | }, 519 | "execution_count": 16, 520 | "metadata": {}, 521 | "output_type": "execute_result" 522 | } 523 | ], 524 | "source": [ 525 | "s1 = \"A random word\"\n", 526 | "s2 = \"A random word\"\n", 527 | "s1 == s2 # False" 528 | ] 529 | }, 530 | { 531 | "cell_type": "code", 532 | "execution_count": 17, 533 | "metadata": {}, 534 | "outputs": [ 535 | { 536 | "data": { 537 | "text/plain": [ 538 | "True" 539 | ] 540 | }, 541 | "execution_count": 17, 542 | "metadata": {}, 543 | "output_type": "execute_result" 544 | } 545 | ], 546 | "source": [ 547 | "s1 = \"Arandomword\"\n", 548 | "s2 = \"Arandomword\"\n", 549 | "s1 == s2 # True" 550 | ] 551 | }, 552 | { 553 | "cell_type": "code", 554 | "execution_count": null, 555 | "metadata": {}, 556 | "outputs": [], 557 | "source": [] 558 | }, 559 | { 560 | "cell_type": "code", 561 | "execution_count": null, 562 | "metadata": {}, 563 | "outputs": [], 564 | "source": [] 565 | } 566 | ], 567 | "metadata": { 568 | "kernelspec": { 569 | "display_name": "Python 3", 570 | "language": "python", 571 | "name": "python3" 572 | }, 573 | "language_info": { 574 | "codemirror_mode": { 575 | "name": "ipython", 576 | "version": 3 577 | }, 578 | "file_extension": ".py", 579 | "mimetype": "text/x-python", 580 | "name": "python", 581 | "nbconvert_exporter": "python", 582 | "pygments_lexer": "ipython3", 583 | "version": "3.6.8" 584 | } 585 | }, 586 | "nbformat": 4, 587 | "nbformat_minor": 2 588 | } 589 | -------------------------------------------------------------------------------- /day2/4_Generator.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 제너레이터(Generator)\n", 8 | "\n", 9 | "- 제너레이터는 반복자(iterator)와 같은 루프의 작용을 컨트롤하기 위해 쓰여지는 특별한 함수 또는 루틴. \n", 10 | "- 제너레이터는 배열이나 리스트를 리턴하는 함수와 비슷하며, 호출을 할 수 있는 파라메터를 가지고 있고, 연속적인 값들을 만들어 냄. \n", 11 | "- 하지만 한번에 모든 값을 포함한 배열을 만들어서 리턴하는 대신에 yield 구문을 이용해 한 번 호출될 때마다 하나의 값만을 리턴하고, 이런 이유로 일반 반복자에 비해 아주 작은 메모리를 필요로 함. \n", 12 | "- 간단히 얘기하면 제너레이터는 반복자와 같은 역할을 하는 함수." 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 1, 18 | "metadata": {}, 19 | "outputs": [ 20 | { 21 | "name": "stdout", 22 | "output_type": "stream", 23 | "text": [ 24 | "[1, 4, 9, 16, 25]\n" 25 | ] 26 | } 27 | ], 28 | "source": [ 29 | "def square_numbers(nums):\n", 30 | " result = []\n", 31 | " for i in nums:\n", 32 | " result.append(i * i)\n", 33 | " return result\n", 34 | "\n", 35 | "mynums = square_numbers([1, 2, 3, 4, 5])\n", 36 | "\n", 37 | "print(mynums)" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "위 코드를 제너레이터로 만들어보기" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 2, 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "name": "stdout", 54 | "output_type": "stream", 55 | "text": [ 56 | "\n" 57 | ] 58 | } 59 | ], 60 | "source": [ 61 | "def square_numbers(nums):\n", 62 | " for i in nums:\n", 63 | " yield i*i\n", 64 | " \n", 65 | "my_nums = square_numbers([1, 2, 3, 4, 5]) #1\n", 66 | "\n", 67 | "print(my_nums)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "#1까지는 아무런 계산을 하지 않고 호출되기를 기다리고 있는 상태임." 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 5, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stdout", 84 | "output_type": "stream", 85 | "text": [ 86 | "1\n", 87 | "4\n", 88 | "9\n", 89 | "16\n" 90 | ] 91 | }, 92 | { 93 | "data": { 94 | "text/plain": [ 95 | "25" 96 | ] 97 | }, 98 | "execution_count": 5, 99 | "metadata": {}, 100 | "output_type": "execute_result" 101 | } 102 | ], 103 | "source": [ 104 | "def square_numbers(nums):\n", 105 | " for i in nums:\n", 106 | " yield i * i\n", 107 | "\n", 108 | "my_nums = square_numbers([1, 2, 3, 4, 5])\n", 109 | "\n", 110 | "print(next(my_nums))\n", 111 | "print(next(my_nums))\n", 112 | "print(next(my_nums))\n", 113 | "print(next(my_nums))\n", 114 | "print(next(my_nums))" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "제너레이터는 일반적으로 for 루프를 통해서 호출함." 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 12, 127 | "metadata": {}, 128 | "outputs": [ 129 | { 130 | "name": "stdout", 131 | "output_type": "stream", 132 | "text": [ 133 | "1\n", 134 | "4\n", 135 | "9\n", 136 | "16\n", 137 | "25\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "def square_numbers(nums):\n", 143 | " for i in nums:\n", 144 | " yield i * i\n", 145 | "\n", 146 | "my_nums = square_numbers([1, 2, 3, 4, 5])\n", 147 | "\n", 148 | "for num in my_nums:\n", 149 | " print(num)" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "**\"list comprehension\"**을 사용하면 위 코드를 더 간단하게 만들 수 있음." 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 13, 162 | "metadata": {}, 163 | "outputs": [ 164 | { 165 | "name": "stdout", 166 | "output_type": "stream", 167 | "text": [ 168 | "[1, 4, 9, 16, 25]\n", 169 | "1\n", 170 | "4\n", 171 | "9\n", 172 | "16\n", 173 | "25\n" 174 | ] 175 | } 176 | ], 177 | "source": [ 178 | "my_nums = [x*x for x in [1, 2, 3, 4, 5]]\n", 179 | "\n", 180 | "print(my_nums)\n", 181 | "\n", 182 | "for num in my_nums:\n", 183 | " print(num)" 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "metadata": {}, 189 | "source": [ 190 | "위 구문을 조금만 바꾸면 제너레이터로 만들 수 있음." 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": 14, 196 | "metadata": {}, 197 | "outputs": [ 198 | { 199 | "name": "stdout", 200 | "output_type": "stream", 201 | "text": [ 202 | " at 0x111ec8410>\n", 203 | "1\n", 204 | "4\n", 205 | "9\n", 206 | "16\n", 207 | "25\n" 208 | ] 209 | } 210 | ], 211 | "source": [ 212 | "my_nums = (x*x for x in [1, 2, 3, 4, 5])\n", 213 | "\n", 214 | "print(my_nums)\n", 215 | "\n", 216 | "for num in my_nums:\n", 217 | " print(num)" 218 | ] 219 | }, 220 | { 221 | "cell_type": "markdown", 222 | "metadata": {}, 223 | "source": [ 224 | "한번에 제너레이터 데이터를 보고싶으면, 리스트로 변환해서 보면됨." 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": 15, 230 | "metadata": {}, 231 | "outputs": [ 232 | { 233 | "name": "stdout", 234 | "output_type": "stream", 235 | "text": [ 236 | " at 0x111e3fa98>\n", 237 | "[1, 4, 9, 16, 25]\n" 238 | ] 239 | } 240 | ], 241 | "source": [ 242 | "# -*- coding: utf-8 -*-\n", 243 | "\n", 244 | "my_nums = (x*x for x in [1, 2, 3, 4, 5]) # 제너레이터 생성\n", 245 | "\n", 246 | "print(my_nums)\n", 247 | "print(list(my_nums)) # 제너레이터를 리스트로 변형" 248 | ] 249 | }, 250 | { 251 | "cell_type": "markdown", 252 | "metadata": {}, 253 | "source": [ 254 | "### 제너레이터의 장점인 성능에 대한 확인." 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "execution_count": 9, 260 | "metadata": {}, 261 | "outputs": [ 262 | { 263 | "name": "stdout", 264 | "output_type": "stream", 265 | "text": [ 266 | "psutil.Process(pid=83779, name='python3.6', started='15:37:53')\n", 267 | "309.23046875\n", 268 | "\n", 269 | "시작 전 메모리 사용량: 309.23046875 MB\n", 270 | "종료 후 메모리 사용량: 572.78515625 MB\n", 271 | "총 소요된 시간: 1.952282 초\n" 272 | ] 273 | } 274 | ], 275 | "source": [ 276 | "# -*- coding: utf-8 -*-\n", 277 | "import os\n", 278 | "import psutil\n", 279 | "import random\n", 280 | "import time\n", 281 | "\n", 282 | "names = ['최용호', '지길정', '진영욱', '김세훈', '오세훈', '김민우']\n", 283 | "majors = ['컴퓨터 공학', '국문학', '영문학', '수학', '정치']\n", 284 | "\n", 285 | "process = psutil.Process(os.getpid())\n", 286 | "mem_before = process.memory_info().rss / 1024 / 1024\n", 287 | "\n", 288 | "def people_list(num_people):\n", 289 | " result = []\n", 290 | " for i in range(num_people):\n", 291 | " person = {\n", 292 | " 'id': i,\n", 293 | " 'name': random.choice(names),\n", 294 | " 'major': random.choice(majors)\n", 295 | " }\n", 296 | " result.append(person)\n", 297 | " return result\n", 298 | "\n", 299 | " \n", 300 | "t1 = time.clock()\n", 301 | "people = people_list(1000000) #1 people_list를 호출\n", 302 | "t2 = time.clock()\n", 303 | "mem_after = process.memory_info().rss / 1024 / 1024\n", 304 | "total_time = t2 - t1\n", 305 | "\n", 306 | "print(process)\n", 307 | "print(mem_before)\n", 308 | "print()\n", 309 | "print('시작 전 메모리 사용량: {} MB'.format(mem_before))\n", 310 | "print('종료 후 메모리 사용량: {} MB'.format(mem_after))\n", 311 | "print('총 소요된 시간: {:.6f} 초'.format(total_time))" 312 | ] 313 | }, 314 | { 315 | "cell_type": "markdown", 316 | "metadata": {}, 317 | "source": [ 318 | "백만명의 학생의 정보가 들어있는 리스트로 테스트 해본결과 메모리 사용량이 40MB에서 303MB로 증가, 소요시간은 2.49초.\n", 319 | "아래의 제너레이터 코드와 비교." 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "execution_count": 1, 325 | "metadata": {}, 326 | "outputs": [ 327 | { 328 | "name": "stdout", 329 | "output_type": "stream", 330 | "text": [ 331 | "psutil.Process(pid=83786, name='python3.6', started='15:41:18')\n", 332 | "46.4296875\n", 333 | "\n", 334 | "시작 전 메모리 사용량: 46.4296875 MB\n", 335 | "종료 후 메모리 사용량: 46.43359375 MB\n", 336 | "총 소요된 시간: 0.000047 초\n" 337 | ] 338 | } 339 | ], 340 | "source": [ 341 | "# -*- coding: utf-8 -*-\n", 342 | "from __future__ import division\n", 343 | "import os\n", 344 | "import psutil\n", 345 | "import random\n", 346 | "import time\n", 347 | "\n", 348 | "names = ['최용호', '지길정', '진영욱', '김세훈', '오세훈', '김민우']\n", 349 | "majors = ['컴퓨터 공학', '국문학', '영문학', '수학', '정치']\n", 350 | "\n", 351 | "process = psutil.Process(os.getpid())\n", 352 | "mem_before = process.memory_info().rss / 1024 / 1024\n", 353 | "\n", 354 | "\n", 355 | "def people_generator(num_people):\n", 356 | " for i in range(num_people):\n", 357 | " person = {\n", 358 | " 'id': i,\n", 359 | " 'name': random.choice(names),\n", 360 | " 'major': random.choice(majors)\n", 361 | " }\n", 362 | " yield person\n", 363 | "\n", 364 | " \n", 365 | "t1 = time.clock()\n", 366 | "people = people_generator(1000000) #1 people_list를 호출\n", 367 | "t2 = time.clock()\n", 368 | "mem_after = process.memory_info().rss / 1024 / 1024\n", 369 | "total_time = t2 - t1\n", 370 | "\n", 371 | "print(process)\n", 372 | "print(mem_before)\n", 373 | "print()\n", 374 | "print('시작 전 메모리 사용량: {} MB'.format(mem_before))\n", 375 | "print('종료 후 메모리 사용량: {} MB'.format(mem_after))\n", 376 | "print('총 소요된 시간: {:.6f} 초'.format(total_time))" 377 | ] 378 | }, 379 | { 380 | "cell_type": "markdown", 381 | "metadata": {}, 382 | "source": [ 383 | "제너레이터를 활용하니 메모리 사용량이 훨씬 적고, 작업시간도 훨씬 빠름. \n", 384 | " \n", 385 | "#### 결론) 제너레이터는 모든 결과값을 메모리에 저장하지 않기 때문에 더 좋은 퍼포먼스를 냄." 386 | ] 387 | }, 388 | { 389 | "cell_type": "markdown", 390 | "metadata": {}, 391 | "source": [ 392 | "---" 393 | ] 394 | } 395 | ], 396 | "metadata": { 397 | "kernelspec": { 398 | "display_name": "Python 3", 399 | "language": "python", 400 | "name": "python3" 401 | }, 402 | "language_info": { 403 | "codemirror_mode": { 404 | "name": "ipython", 405 | "version": 3 406 | }, 407 | "file_extension": ".py", 408 | "mimetype": "text/x-python", 409 | "name": "python", 410 | "nbconvert_exporter": "python", 411 | "pygments_lexer": "ipython3", 412 | "version": "3.6.7" 413 | } 414 | }, 415 | "nbformat": 4, 416 | "nbformat_minor": 2 417 | } 418 | -------------------------------------------------------------------------------- /day2/4_Iterator.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Iterable 과 Iterator" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "### 1-1 Iterable \n", 15 | "- iterable 객체 - 반복 가능한 객체\n", 16 | "- 대표적으로 iterable한 타입 : list, dict, set, str, bytes, tuple, range\n", 17 | "\n", 18 | "### 1-2 Iterator \n", 19 | "- iterator 객체 : 값을 차례대로 꺼낼 수 있는 객체.\n", 20 | "- iterator는 iterable한 객체를 내장함수 또는 iterable객체의 메소드로 객체를 생성가능.\n", 21 | "- 파이썬 내장함수 iter()를 사용해 iterator 객체를 생성. REPL을 실행." 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 7, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "data": { 31 | "text/plain": [ 32 | "list_iterator" 33 | ] 34 | }, 35 | "execution_count": 7, 36 | "metadata": {}, 37 | "output_type": "execute_result" 38 | } 39 | ], 40 | "source": [ 41 | "a = [1, 2, 3]\n", 42 | "a_iter = iter(a)\n", 43 | "type(a_iter)" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "- iterable한 객체는 매직메소드 __iter__ 메소드를 가지고 있습니다. 이 메소드로 iterator를 만들어보기." 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 20, 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "data": { 60 | "text/plain": [ 61 | "['__and__',\n", 62 | " '__class__',\n", 63 | " '__contains__',\n", 64 | " '__delattr__',\n", 65 | " '__dir__',\n", 66 | " '__doc__',\n", 67 | " '__eq__',\n", 68 | " '__format__',\n", 69 | " '__ge__',\n", 70 | " '__getattribute__',\n", 71 | " '__gt__',\n", 72 | " '__hash__',\n", 73 | " '__iand__',\n", 74 | " '__init__',\n", 75 | " '__init_subclass__',\n", 76 | " '__ior__',\n", 77 | " '__isub__',\n", 78 | " '__iter__',\n", 79 | " '__ixor__',\n", 80 | " '__le__',\n", 81 | " '__len__',\n", 82 | " '__lt__',\n", 83 | " '__ne__',\n", 84 | " '__new__',\n", 85 | " '__or__',\n", 86 | " '__rand__',\n", 87 | " '__reduce__',\n", 88 | " '__reduce_ex__',\n", 89 | " '__repr__',\n", 90 | " '__ror__',\n", 91 | " '__rsub__',\n", 92 | " '__rxor__',\n", 93 | " '__setattr__',\n", 94 | " '__sizeof__',\n", 95 | " '__str__',\n", 96 | " '__sub__',\n", 97 | " '__subclasshook__',\n", 98 | " '__xor__',\n", 99 | " 'add',\n", 100 | " 'clear',\n", 101 | " 'copy',\n", 102 | " 'difference',\n", 103 | " 'difference_update',\n", 104 | " 'discard',\n", 105 | " 'intersection',\n", 106 | " 'intersection_update',\n", 107 | " 'isdisjoint',\n", 108 | " 'issubset',\n", 109 | " 'issuperset',\n", 110 | " 'pop',\n", 111 | " 'remove',\n", 112 | " 'symmetric_difference',\n", 113 | " 'symmetric_difference_update',\n", 114 | " 'union',\n", 115 | " 'update']" 116 | ] 117 | }, 118 | "execution_count": 20, 119 | "metadata": {}, 120 | "output_type": "execute_result" 121 | } 122 | ], 123 | "source": [ 124 | "b = {1, 2, 3}\n", 125 | "dir(b)" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": 21, 131 | "metadata": {}, 132 | "outputs": [ 133 | { 134 | "data": { 135 | "text/plain": [ 136 | "set_iterator" 137 | ] 138 | }, 139 | "execution_count": 21, 140 | "metadata": {}, 141 | "output_type": "execute_result" 142 | } 143 | ], 144 | "source": [ 145 | "b_iter = b.__iter__()\n", 146 | "type(b_iter)" 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "iterator는 값을 차례대로 꺼낼 수 있는 객체. \n", 154 | "next 내장함수를 사용하여 첫번째, 두번째, 세번째 값을 출력. \n", 155 | "네번째 실행에서는 StopIteration 이라는 예외가 발생." 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 9, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "data": { 165 | "text/plain": [ 166 | "1" 167 | ] 168 | }, 169 | "execution_count": 9, 170 | "metadata": {}, 171 | "output_type": "execute_result" 172 | } 173 | ], 174 | "source": [ 175 | "next(a_iter)" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 10, 181 | "metadata": {}, 182 | "outputs": [ 183 | { 184 | "data": { 185 | "text/plain": [ 186 | "2" 187 | ] 188 | }, 189 | "execution_count": 10, 190 | "metadata": {}, 191 | "output_type": "execute_result" 192 | } 193 | ], 194 | "source": [ 195 | "next(a_iter)" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 11, 201 | "metadata": {}, 202 | "outputs": [ 203 | { 204 | "data": { 205 | "text/plain": [ 206 | "3" 207 | ] 208 | }, 209 | "execution_count": 11, 210 | "metadata": {}, 211 | "output_type": "execute_result" 212 | } 213 | ], 214 | "source": [ 215 | "next(a_iter)" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": 12, 221 | "metadata": {}, 222 | "outputs": [ 223 | { 224 | "ename": "StopIteration", 225 | "evalue": "", 226 | "output_type": "error", 227 | "traceback": [ 228 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 229 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 230 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma_iter\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 231 | "\u001b[0;31mStopIteration\u001b[0m: " 232 | ] 233 | } 234 | ], 235 | "source": [ 236 | "next(a_iter)" 237 | ] 238 | }, 239 | { 240 | "cell_type": "markdown", 241 | "metadata": {}, 242 | "source": [ 243 | "iterator 매직 메소드 'next'를 통해 하나씩 값을 꺼내보기" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 13, 249 | "metadata": {}, 250 | "outputs": [ 251 | { 252 | "data": { 253 | "text/plain": [ 254 | "1" 255 | ] 256 | }, 257 | "execution_count": 13, 258 | "metadata": {}, 259 | "output_type": "execute_result" 260 | } 261 | ], 262 | "source": [ 263 | "b_iter.__next__()" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": 14, 269 | "metadata": {}, 270 | "outputs": [ 271 | { 272 | "data": { 273 | "text/plain": [ 274 | "2" 275 | ] 276 | }, 277 | "execution_count": 14, 278 | "metadata": {}, 279 | "output_type": "execute_result" 280 | } 281 | ], 282 | "source": [ 283 | "b_iter.__next__()" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": 15, 289 | "metadata": {}, 290 | "outputs": [ 291 | { 292 | "data": { 293 | "text/plain": [ 294 | "3" 295 | ] 296 | }, 297 | "execution_count": 15, 298 | "metadata": {}, 299 | "output_type": "execute_result" 300 | } 301 | ], 302 | "source": [ 303 | "b_iter.__next__()" 304 | ] 305 | }, 306 | { 307 | "cell_type": "code", 308 | "execution_count": 16, 309 | "metadata": {}, 310 | "outputs": [ 311 | { 312 | "ename": "StopIteration", 313 | "evalue": "", 314 | "output_type": "error", 315 | "traceback": [ 316 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 317 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 318 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mb_iter\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__next__\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[0m", 319 | "\u001b[0;31mStopIteration\u001b[0m: " 320 | ] 321 | } 322 | ], 323 | "source": [ 324 | "b_iter.__next__()" 325 | ] 326 | }, 327 | { 328 | "cell_type": "code", 329 | "execution_count": null, 330 | "metadata": {}, 331 | "outputs": [], 332 | "source": [] 333 | } 334 | ], 335 | "metadata": { 336 | "kernelspec": { 337 | "display_name": "Python 3", 338 | "language": "python", 339 | "name": "python3" 340 | }, 341 | "language_info": { 342 | "codemirror_mode": { 343 | "name": "ipython", 344 | "version": 3 345 | }, 346 | "file_extension": ".py", 347 | "mimetype": "text/x-python", 348 | "name": "python", 349 | "nbconvert_exporter": "python", 350 | "pygments_lexer": "ipython3", 351 | "version": "3.6.7" 352 | } 353 | }, 354 | "nbformat": 4, 355 | "nbformat_minor": 2 356 | } 357 | -------------------------------------------------------------------------------- /day2/5_set.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Set 함수\n", 8 | "- 데이터 안에서 중복된 값을 필터링 하는데 쓰는 함수\n", 9 | "- 중복제거 하고자 하는 데이터 앞에 set을 넣어서 사용" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "[참고] set의 생성방식" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 24, 22 | "metadata": {}, 23 | "outputs": [ 24 | { 25 | "name": "stdout", 26 | "output_type": "stream", 27 | "text": [ 28 | "\n", 29 | "\n" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "data = [1,2,3,4,5]\n", 35 | "\n", 36 | "#방법 1: set(data)\n", 37 | "data_set = set(data)\n", 38 | "print(type(data_set))\n", 39 | "\n", 40 | "#방법 2: {}\n", 41 | "data_set_2 = {1,2,3,4,5}\n", 42 | "print(type(data_set))" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 10, 48 | "metadata": {}, 49 | "outputs": [ 50 | { 51 | "name": "stdout", 52 | "output_type": "stream", 53 | "text": [ 54 | "set전: [1, 2, 3, 4, 5, 5, 5]\n", 55 | "set후: {1, 2, 3, 4, 5}\n" 56 | ] 57 | } 58 | ], 59 | "source": [ 60 | "temp_list = [1,2,3,4,5,5,5]\n", 61 | "print(\"set전:\",temp_list)\n", 62 | "temp_set = set(temp_list)\n", 63 | "print(\"set후:\",temp_set)" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 11, 69 | "metadata": {}, 70 | "outputs": [ 71 | { 72 | "name": "stdout", 73 | "output_type": "stream", 74 | "text": [ 75 | "set전: ['a', 'b', 'c', 'd', 'e', 'f', 'c']\n", 76 | "set후: {'e', 'b', 'c', 'a', 'd', 'f'}\n" 77 | ] 78 | } 79 | ], 80 | "source": [ 81 | "temp_list = ['a','b','c','d','e','f','c']\n", 82 | "print(\"set전:\",temp_list)\n", 83 | "temp_set = set(temp_list)\n", 84 | "print(\"set후:\",temp_set)" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": {}, 90 | "source": [ 91 | "### 중복된 값만 추출하고 싶은 경우" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 12, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "name": "stdout", 101 | "output_type": "stream", 102 | "text": [ 103 | "{'a', 'c'}\n" 104 | ] 105 | } 106 | ], 107 | "source": [ 108 | "temp_list = ['a','c','d','e','a','f','c']\n", 109 | "duplicated = set([x for x in temp_list if temp_list.count(x) > 1])\n", 110 | "print(duplicated)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "### 교집합, 합집합, 차집합" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 20, 123 | "metadata": { 124 | "scrolled": true 125 | }, 126 | "outputs": [ 127 | { 128 | "name": "stdout", 129 | "output_type": "stream", 130 | "text": [ 131 | "{'red'}\n" 132 | ] 133 | }, 134 | { 135 | "data": { 136 | "text/plain": [ 137 | "{'black', 'blue', 'brown', 'green', 'red', 'yellow'}" 138 | ] 139 | }, 140 | "execution_count": 20, 141 | "metadata": {}, 142 | "output_type": "execute_result" 143 | } 144 | ], 145 | "source": [ 146 | "# 교집합\n", 147 | "\n", 148 | "set_1 = set(['yellow', 'red', 'blue', 'green', 'black']) #기준\n", 149 | "set_2 = set(['red', 'brown'])\n", 150 | "print(set_1.intersection(set_2))" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 21, 156 | "metadata": {}, 157 | "outputs": [ 158 | { 159 | "name": "stdout", 160 | "output_type": "stream", 161 | "text": [ 162 | "{'green', 'brown', 'yellow', 'blue', 'black', 'red'}\n" 163 | ] 164 | } 165 | ], 166 | "source": [ 167 | "# 합집합\n", 168 | "\n", 169 | "set_1 = set(['yellow', 'red', 'blue', 'green', 'black']) #기준\n", 170 | "set_2 = set(['red', 'brown'])\n", 171 | "print(set_1.union(set_2))" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": 19, 177 | "metadata": {}, 178 | "outputs": [ 179 | { 180 | "name": "stdout", 181 | "output_type": "stream", 182 | "text": [ 183 | "set_1이 기준: {'green', 'black', 'blue', 'yellow'}\n", 184 | "set_2가 기준: {'brown'}\n" 185 | ] 186 | } 187 | ], 188 | "source": [ 189 | "# 차집합\n", 190 | "\n", 191 | "set_1 = set(['yellow', 'red', 'blue', 'green', 'black']) \n", 192 | "set_2 = set(['red', 'brown'])\n", 193 | "print(\"set_1이 기준:\", set_1.difference(set_2)) #set_1가 기준\n", 194 | "print(\"set_2가 기준:\", set_2.difference(set_1)) #set_2가 기준" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "### set의 특징\n", 202 | "- list(indexing, slicing모두 가능), dictionary(indexing만 가능)와는 달리, indexing과 slicing 모두 안됨" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 25, 208 | "metadata": {}, 209 | "outputs": [], 210 | "source": [ 211 | "temp_list = [1,2,3,4,5]\n", 212 | "temp_dict = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}\n", 213 | "temp_set = {1,2,3,4,5}" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 29, 219 | "metadata": {}, 220 | "outputs": [ 221 | { 222 | "name": "stdout", 223 | "output_type": "stream", 224 | "text": [ 225 | "2\n", 226 | "[1, 2, 3]\n" 227 | ] 228 | } 229 | ], 230 | "source": [ 231 | "print(temp_list[1])\n", 232 | "print(temp_list[:3])" 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": 33, 238 | "metadata": {}, 239 | "outputs": [ 240 | { 241 | "name": "stdout", 242 | "output_type": "stream", 243 | "text": [ 244 | "1\n" 245 | ] 246 | } 247 | ], 248 | "source": [ 249 | "print(temp_dict['a'])\n", 250 | "# print(temp_dict['a':'c'])" 251 | ] 252 | }, 253 | { 254 | "cell_type": "code", 255 | "execution_count": 34, 256 | "metadata": { 257 | "scrolled": true 258 | }, 259 | "outputs": [ 260 | { 261 | "ename": "TypeError", 262 | "evalue": "'set' object does not support indexing", 263 | "output_type": "error", 264 | "traceback": [ 265 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 266 | "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", 267 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtemp_set\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtemp_set\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 268 | "\u001b[1;31mTypeError\u001b[0m: 'set' object does not support indexing" 269 | ] 270 | } 271 | ], 272 | "source": [ 273 | "print(temp_set[0])\n", 274 | "print(temp_set[:3])" 275 | ] 276 | }, 277 | { 278 | "cell_type": "markdown", 279 | "metadata": {}, 280 | "source": [ 281 | "### 속도비교\n", 282 | "- list, set, dict" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 100, 288 | "metadata": {}, 289 | "outputs": [ 290 | { 291 | "name": "stdout", 292 | "output_type": "stream", 293 | "text": [ 294 | "9.479959119029445\n", 295 | "13.34767472684507\n", 296 | "0.0002879998864955269\n", 297 | "0.00027693816264218185\n" 298 | ] 299 | } 300 | ], 301 | "source": [ 302 | "figure_iteration_list = [num for num in range(1000001)]\n", 303 | "keys = [key for key in range(100,1000101)]\n", 304 | "values = [value for value in range(1000001)]\n", 305 | "\n", 306 | "from timeit import timeit\n", 307 | "\n", 308 | "def test_iter(data):\n", 309 | " for i in data:\n", 310 | " pass\n", 311 | "\n", 312 | "def test_iter_dict(data):\n", 313 | " for key, value in data.items():\n", 314 | " pass\n", 315 | " \n", 316 | "iter_numbers=1000\n", 317 | "\n", 318 | "#list\n", 319 | "print(timeit('test_iter(data)', number=iter_numbers, \n", 320 | " setup=\"from __main__ import test_iter; \\\n", 321 | " data=list(num for num in range(1000001))\"))\n", 322 | "#set\n", 323 | "print(timeit('test_iter(data)', number=iter_numbers, \n", 324 | " setup=\"from __main__ import test_iter; \\\n", 325 | " data=set(num for num in range(1000001))\"))\n", 326 | "#dict (key)\n", 327 | "print(timeit('test_iter(data)', number=iter_numbers, \n", 328 | " setup=\"from __main__ import test_iter; \\\n", 329 | " data=dict(key=[key for key in range(100,1010001)], value=[value for value in range(1000001)])\"))\n", 330 | "#dict (key, value)\n", 331 | "print(timeit('test_iter_dict(data)', number=iter_numbers, \n", 332 | " setup=\"from __main__ import test_iter_dict; \\\n", 333 | " data=dict(key=[key for key in range(100,1010001)], value=[value for value in range(1000001)])\"))" 334 | ] 335 | }, 336 | { 337 | "cell_type": "code", 338 | "execution_count": 121, 339 | "metadata": {}, 340 | "outputs": [ 341 | { 342 | "name": "stdout", 343 | "output_type": "stream", 344 | "text": [ 345 | "6.71 ms ± 121 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", 346 | "13.9 ms ± 179 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" 347 | ] 348 | } 349 | ], 350 | "source": [ 351 | "figure_iteration_list = [num for num in range(100001)]\n", 352 | "keys = [key for key in range(100,100101)]\n", 353 | "values = [value for value in range(100001)]\n", 354 | "figure_iteration_dict = dict(zip(keys, values))\n", 355 | "\n", 356 | "def test_list(data):\n", 357 | " list_blank = []\n", 358 | " for i in data:\n", 359 | " list_blank.append(i)\n", 360 | " return list_blank\n", 361 | "\n", 362 | "def test_dict(data):\n", 363 | " dict_blank = {}\n", 364 | " for key_n, value_n in data.items():\n", 365 | " dict_blank[key_n] = value_n\n", 366 | " return dict_blank\n", 367 | "\n", 368 | "# list_blank = test_list(figure_iteration_list)\n", 369 | "# dict_blank = test_dict(figure_iteration_dict)\n", 370 | "\n", 371 | "%timeit test_list(figure_iteration_list)\n", 372 | "%timeit test_dict(figure_iteration_dict)" 373 | ] 374 | }, 375 | { 376 | "cell_type": "markdown", 377 | "metadata": {}, 378 | "source": [ 379 | "### Python list 성능구조 분석" 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": 1, 385 | "metadata": {}, 386 | "outputs": [ 387 | { 388 | "name": "stdout", 389 | "output_type": "stream", 390 | "text": [ 391 | "걸린시간 : 2.99e-03\n" 392 | ] 393 | } 394 | ], 395 | "source": [ 396 | "def makeListUsingAppend(N):\n", 397 | " result = []\n", 398 | " for i in range(N):\n", 399 | " result.append(i)\n", 400 | " return result\n", 401 | "\n", 402 | "from time import time\n", 403 | "t0 = time()\n", 404 | "makeListUsingAppend(10000)\n", 405 | "print (\"걸린시간 : %.2e\" % (time()-t0))" 406 | ] 407 | }, 408 | { 409 | "cell_type": "code", 410 | "execution_count": 5, 411 | "metadata": { 412 | "scrolled": false 413 | }, 414 | "outputs": [ 415 | { 416 | "name": "stdout", 417 | "output_type": "stream", 418 | "text": [ 419 | "걸린시간 : 9.97e-04\n" 420 | ] 421 | } 422 | ], 423 | "source": [ 424 | "def makeListUsingBulkAlloc(N):\n", 425 | " result = [0]*N #한번에 N개의 공간을 0으로 채우는 방법입니다.\n", 426 | " for i in range(N):\n", 427 | " result[i] = i\n", 428 | " return result\n", 429 | "\n", 430 | "t0 = time()\n", 431 | "makeListUsingBulkAlloc(10000)\n", 432 | "print (\"걸린시간 : %.2e\" % (time()-t0))" 433 | ] 434 | } 435 | ], 436 | "metadata": { 437 | "kernelspec": { 438 | "display_name": "Python 3", 439 | "language": "python", 440 | "name": "python3" 441 | }, 442 | "language_info": { 443 | "codemirror_mode": { 444 | "name": "ipython", 445 | "version": 3 446 | }, 447 | "file_extension": ".py", 448 | "mimetype": "text/x-python", 449 | "name": "python", 450 | "nbconvert_exporter": "python", 451 | "pygments_lexer": "ipython3", 452 | "version": "3.6.5" 453 | } 454 | }, 455 | "nbformat": 4, 456 | "nbformat_minor": 2 457 | } 458 | -------------------------------------------------------------------------------- /day2/6_mutation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 9. 변형 (Mutation)\n", 8 | "참고자료\n", 9 | " - https://medium.com/@meghamohan/mutable-and-immutable-side-of-python-c2145cf72747\n", 10 | " - https://medium.com/@birnbera/objects-memory-and-mutation-in-python-810bf090b63c" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "## Python 기본 자료형의 변형 가능 여부" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "| Class | Mutable |\n", 25 | "|:---:|:---:|\n", 26 | "| bool | X |\n", 27 | "| int | X |\n", 28 | "| float | X |\n", 29 | "| list | O |\n", 30 | "| tuple | X |\n", 31 | "| str | X |\n", 32 | "| set | O |\n", 33 | "| frozenset | X |\n", 34 | "| dict | O |" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "## 예시\n", 42 | "### List" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 1, 48 | "metadata": {}, 49 | "outputs": [ 50 | { 51 | "name": "stdout", 52 | "output_type": "stream", 53 | "text": [ 54 | "['hi']\n" 55 | ] 56 | } 57 | ], 58 | "source": [ 59 | "foo = ['hi']\n", 60 | "print(foo) # ['hi']" 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "bar에 'bye'를 추가했지만 bar와 foo가 동일한 주소를 참조하고 있어 foo의 참조 값도 같이 변경" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 2, 73 | "metadata": {}, 74 | "outputs": [ 75 | { 76 | "name": "stdout", 77 | "output_type": "stream", 78 | "text": [ 79 | "['hi', 'bye']\n" 80 | ] 81 | } 82 | ], 83 | "source": [ 84 | "bar = foo\n", 85 | "bar += ['bye']\n", 86 | "print(foo) # ['hi', 'bye']" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 3, 92 | "metadata": {}, 93 | "outputs": [ 94 | { 95 | "name": "stdout", 96 | "output_type": "stream", 97 | "text": [ 98 | "0x24a5d352fc8 \n", 99 | "0x24a5d352fc8 \n", 100 | "True\n" 101 | ] 102 | } 103 | ], 104 | "source": [ 105 | "print(hex(id(foo)), type(foo)) # 0x24a5d352fc8 \n", 106 | "print(hex(id(bar)), type(bar)) # 0x24a5d352fc8 \n", 107 | "print(foo == bar) # True" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "### Integer\n", 115 | "int도 유사하지만 약간의 차이가 있다\n", 116 | "\n", 117 | "예시) 10이라는 정수 자체가 이미 메모리에 할당돼 있어 x는 해당 주소를 참조하는 형태" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 4, 123 | "metadata": {}, 124 | "outputs": [ 125 | { 126 | "name": "stdout", 127 | "output_type": "stream", 128 | "text": [ 129 | "True\n", 130 | "True\n", 131 | "True\n", 132 | "0x7459b200\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "x = 10\n", 138 | "y = x\n", 139 | "\n", 140 | "print(id(x) == id(y)) # True\n", 141 | "print(id(x) == id(10)) # True\n", 142 | "print(id(y) == id(10)) # True\n", 143 | "print(hex(id(10))) # 0x7459b200" 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": {}, 149 | "source": [ 150 | "따라서 x += 1을 해줄 경우 x의 주소가 변하는 것처럼 결과가 나오는데 이는 사실 x가 11을 참조하기 때문" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 5, 156 | "metadata": {}, 157 | "outputs": [ 158 | { 159 | "name": "stdout", 160 | "output_type": "stream", 161 | "text": [ 162 | "False\n", 163 | "True\n", 164 | "True\n", 165 | "0x7459b200\n", 166 | "0x7459b220\n" 167 | ] 168 | } 169 | ], 170 | "source": [ 171 | "x += 1\n", 172 | "\n", 173 | "print(id(x) == id(y)) # False\n", 174 | "print(id(x) == id(11)) # True\n", 175 | "print(id(y) == id(10)) # True\n", 176 | "print(hex(id(10))) # 0x7459b200\n", 177 | "print(hex(id(11))) # 0x7459b220" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 6, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "name": "stdout", 187 | "output_type": "stream", 188 | "text": [ 189 | "True\n", 190 | "True\n", 191 | "0x7459b220\n" 192 | ] 193 | } 194 | ], 195 | "source": [ 196 | "y += 1\n", 197 | "\n", 198 | "print(id(x) == id(y)) # True\n", 199 | "print(id(x) == id(11)) # True\n", 200 | "print(hex(id(11))) # 0x7459b220" 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": {}, 206 | "source": [ 207 | "### Tuple은 과연 불변할까?\n", 208 | "Tuple은 파이썬의 대표적인 불변 자료형인데 Tuple의 요소는 충분히 변형 가능하다" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 7, 214 | "metadata": {}, 215 | "outputs": [ 216 | { 217 | "name": "stdout", 218 | "output_type": "stream", 219 | "text": [ 220 | "('holberton', [1, 2, 3])\n", 221 | "False\n" 222 | ] 223 | } 224 | ], 225 | "source": [ 226 | "s = ('holberton', [1, 2, 3])\n", 227 | "t = s\n", 228 | "s += (5,)\n", 229 | "print(t) # ('holberton', [1, 2, 3])\n", 230 | "print(id(s) == id(t)) # False" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 8, 236 | "metadata": {}, 237 | "outputs": [ 238 | { 239 | "ename": "TypeError", 240 | "evalue": "'tuple' object does not support item assignment", 241 | "output_type": "error", 242 | "traceback": [ 243 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 244 | "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", 245 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0ms\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;31m# Error\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 246 | "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" 247 | ] 248 | } 249 | ], 250 | "source": [ 251 | "s[1] += [5,] # Error" 252 | ] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "metadata": {}, 257 | "source": [ 258 | "하지만 실제 s\\[1\\]이 참조하고 있는 list에는 새 요소가 추가됐으며 t도 동일한 주소를 참조하고 있기 때문에 t에도 반영" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": 9, 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "name": "stdout", 268 | "output_type": "stream", 269 | "text": [ 270 | "('holberton', [1, 2, 3, 5], 5)\n", 271 | "('holberton', [1, 2, 3, 5])\n", 272 | "0x24a5cf51e48\n", 273 | "False\n" 274 | ] 275 | } 276 | ], 277 | "source": [ 278 | "print(s) # ('holberton', [1, 2, 3, 5], 5)\n", 279 | "print(t) # ('holberton', [1, 2, 3, 5])\n", 280 | "print(hex(id(s[1]))) # 0x24a5cf51e48\n", 281 | "print(id(s) == id(t)) # False" 282 | ] 283 | }, 284 | { 285 | "cell_type": "markdown", 286 | "metadata": {}, 287 | "source": [ 288 | "### 참조에 의한 호출\n", 289 | "참조(변형 가능한) 객체를 함수의 인자로 넘기기 때문에 실제로 함수 내에서 이뤄진 연산이 해당 객체에 반영" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": 10, 295 | "metadata": {}, 296 | "outputs": [ 297 | { 298 | "name": "stdout", 299 | "output_type": "stream", 300 | "text": [ 301 | "0x24a5d4094c8\n", 302 | "[5, 6, 10]\n", 303 | "0x24a5d4094c8\n" 304 | ] 305 | } 306 | ], 307 | "source": [ 308 | "def updateList(list1):\n", 309 | " list1 += [10]\n", 310 | "\n", 311 | "n = [5, 6]\n", 312 | "print(hex(id(n))) # 0x24a5d4094c8\n", 313 | "updateList(n)\n", 314 | "print(n) # [5, 6, 10]\n", 315 | "print(hex(id(n))) # 0x24a5d4094c8" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "### 값에 의한 호출\n", 323 | "하지만 아래와 같은 경우 객체가 참조하고 있는 값만을 넘겨주기 때문에 해당 함수를 호출하는 동안에만 참조 객체가 변경" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": 11, 329 | "metadata": {}, 330 | "outputs": [ 331 | { 332 | "name": "stdout", 333 | "output_type": "stream", 334 | "text": [ 335 | "0x7459b160\n", 336 | "0x7459b160 15 0x7459b2a0\n", 337 | "5\n" 338 | ] 339 | } 340 | ], 341 | "source": [ 342 | "def updateNumber(n):\n", 343 | " tmp = hex(id(n))\n", 344 | " n += 10\n", 345 | " print(tmp, n, hex(id(n)))\n", 346 | "\n", 347 | "b = 5\n", 348 | "updateNumber(b) # 0x7459b160 15 0x7459b2a0\n", 349 | "print(b) # 5" 350 | ] 351 | }, 352 | { 353 | "cell_type": "markdown", 354 | "metadata": {}, 355 | "source": [ 356 | "### 기타" 357 | ] 358 | }, 359 | { 360 | "cell_type": "markdown", 361 | "metadata": {}, 362 | "source": [ 363 | "257 이상의 숫자는 동적으로 메모리에 할당" 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": 23, 369 | "metadata": {}, 370 | "outputs": [ 371 | { 372 | "name": "stdout", 373 | "output_type": "stream", 374 | "text": [ 375 | "0x24a5d3fcfb0\n", 376 | "False\n", 377 | "False\n" 378 | ] 379 | } 380 | ], 381 | "source": [ 382 | "a = 257\n", 383 | "print(hex(id(a))) # 0x24a5d3fcfb0\n", 384 | "b = 257\n", 385 | "print(id(b) == id(a)) # False\n", 386 | "print(id(b) == id(257)) # False" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "정수는 32 byte C struct array에 저장" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": 24, 399 | "metadata": {}, 400 | "outputs": [ 401 | { 402 | "data": { 403 | "text/plain": [ 404 | "True" 405 | ] 406 | }, 407 | "execution_count": 24, 408 | "metadata": {}, 409 | "output_type": "execute_result" 410 | } 411 | ], 412 | "source": [ 413 | "id(10) - id(9) == id(9) - id(8) == id(8) - id(7) == 32 # True" 414 | ] 415 | }, 416 | { 417 | "cell_type": "code", 418 | "execution_count": 25, 419 | "metadata": {}, 420 | "outputs": [ 421 | { 422 | "data": { 423 | "text/plain": [ 424 | "True" 425 | ] 426 | }, 427 | "execution_count": 25, 428 | "metadata": {}, 429 | "output_type": "execute_result" 430 | } 431 | ], 432 | "source": [ 433 | "b = a\n", 434 | "id(b) == id(a) # True" 435 | ] 436 | }, 437 | { 438 | "cell_type": "markdown", 439 | "metadata": {}, 440 | "source": [ 441 | "하지만 257 이상의 숫자도 정수형이기 때문에 연산을 할 경우 새 객체를 생성" 442 | ] 443 | }, 444 | { 445 | "cell_type": "code", 446 | "execution_count": 26, 447 | "metadata": {}, 448 | "outputs": [ 449 | { 450 | "name": "stdout", 451 | "output_type": "stream", 452 | "text": [ 453 | "0x24a5d3fcfb0\n", 454 | "258 0x24a5d1ef470\n" 455 | ] 456 | } 457 | ], 458 | "source": [ 459 | "print(hex(id(b))) # 0x24a5d3fcfb0\n", 460 | "b += 1\n", 461 | "print(b, hex(id(b))) # 258 0x24a5d326ad0" 462 | ] 463 | }, 464 | { 465 | "cell_type": "markdown", 466 | "metadata": {}, 467 | "source": [ 468 | "동일하게 두 list의 요소를 추가하는 코드라도 inline 함수와 풀어서 쓰는 경우 차이가 있다" 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": 27, 474 | "metadata": {}, 475 | "outputs": [ 476 | { 477 | "name": "stdout", 478 | "output_type": "stream", 479 | "text": [ 480 | "0x24a5d46bbc8\n", 481 | "[1, 2, 1, 2] 0x24a5d46bd48\n", 482 | "[1, 2, 1, 2, 1, 2, 1, 2] 0x24a5d46bd48\n", 483 | "[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2] 0x24a5d46bd48\n" 484 | ] 485 | } 486 | ], 487 | "source": [ 488 | "a = [1, 2]\n", 489 | "print(hex(id(a))) # 0x24a5d46bbc8\n", 490 | "\n", 491 | "a = a + a\n", 492 | "print(a, hex(id(a))) # [1, 2, 1, 2] 0x24a5d46bd48\n", 493 | "\n", 494 | "a *= 2\n", 495 | "print(a, hex(id(a))) # [1, 2, 1, 2, 1, 2, 1, 2] 0x24a5d46bd48\n", 496 | "\n", 497 | "a += a\n", 498 | "print(a, hex(id(a))) # [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2] 0x24a5d46bd48" 499 | ] 500 | }, 501 | { 502 | "cell_type": "markdown", 503 | "metadata": {}, 504 | "source": [ 505 | "문자열의 경우도 특정 길이 이하의 문자열에 대해서는 정수와 동일한 방식으로 저장 및 참조" 506 | ] 507 | }, 508 | { 509 | "cell_type": "code", 510 | "execution_count": 16, 511 | "metadata": {}, 512 | "outputs": [ 513 | { 514 | "data": { 515 | "text/plain": [ 516 | "False" 517 | ] 518 | }, 519 | "execution_count": 16, 520 | "metadata": {}, 521 | "output_type": "execute_result" 522 | } 523 | ], 524 | "source": [ 525 | "s1 = \"A random word\"\n", 526 | "s2 = \"A random word\"\n", 527 | "s1 == s2 # False" 528 | ] 529 | }, 530 | { 531 | "cell_type": "code", 532 | "execution_count": 17, 533 | "metadata": {}, 534 | "outputs": [ 535 | { 536 | "data": { 537 | "text/plain": [ 538 | "True" 539 | ] 540 | }, 541 | "execution_count": 17, 542 | "metadata": {}, 543 | "output_type": "execute_result" 544 | } 545 | ], 546 | "source": [ 547 | "s1 = \"Arandomword\"\n", 548 | "s2 = \"Arandomword\"\n", 549 | "s1 == s2 # True" 550 | ] 551 | }, 552 | { 553 | "cell_type": "code", 554 | "execution_count": null, 555 | "metadata": {}, 556 | "outputs": [], 557 | "source": [] 558 | }, 559 | { 560 | "cell_type": "code", 561 | "execution_count": null, 562 | "metadata": {}, 563 | "outputs": [], 564 | "source": [] 565 | } 566 | ], 567 | "metadata": { 568 | "kernelspec": { 569 | "display_name": "Python 3", 570 | "language": "python", 571 | "name": "python3" 572 | }, 573 | "language_info": { 574 | "codemirror_mode": { 575 | "name": "ipython", 576 | "version": 3 577 | }, 578 | "file_extension": ".py", 579 | "mimetype": "text/x-python", 580 | "name": "python", 581 | "nbconvert_exporter": "python", 582 | "pygments_lexer": "ipython3", 583 | "version": "3.6.8" 584 | } 585 | }, 586 | "nbformat": 4, 587 | "nbformat_minor": 2 588 | } 589 | -------------------------------------------------------------------------------- /day2/8_scope/__pycache__/first.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaggleBreak/interpy-kr/6a5e045e2ee3d1a72ea78659c8cb51b5219a9904/day2/8_scope/__pycache__/first.cpython-36.pyc -------------------------------------------------------------------------------- /day2/8_scope/__pycache__/thismod.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaggleBreak/interpy-kr/6a5e045e2ee3d1a72ea78659c8cb51b5219a9904/day2/8_scope/__pycache__/thismod.cpython-36.pyc -------------------------------------------------------------------------------- /day2/8_scope/data.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 -------------------------------------------------------------------------------- /day2/8_scope/first.py: -------------------------------------------------------------------------------- 1 | X = 99 2 | 3 | def set_X(new): 4 | global X 5 | X = new -------------------------------------------------------------------------------- /day2/8_scope/img/scope_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaggleBreak/interpy-kr/6a5e045e2ee3d1a72ea78659c8cb51b5219a9904/day2/8_scope/img/scope_diagram.jpg -------------------------------------------------------------------------------- /day2/8_scope/thismod.py: -------------------------------------------------------------------------------- 1 | var = 99 2 | 3 | def local(): 4 | var = 0 5 | 6 | def glob1(): 7 | global var 8 | var += 1 9 | 10 | def glob2(): 11 | var = 0 12 | import thismod # 자기자신을 임포트 13 | thismod.var += 1 # 전역변수는 그 모듈의 속성이다. 14 | 15 | def glob3(): 16 | var = 0 17 | import sys 18 | glob = sys.modules['thismod'] 19 | glob.var += 1 20 | 21 | def test(): 22 | print(var) 23 | local() 24 | glob1() 25 | glob2() 26 | glob3() 27 | print(var) -------------------------------------------------------------------------------- /day3/09_ternary_op.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 3항 연산자 (Ternary Operator)\n", 8 | "

3항 연산자는 한 종류밖에 없기 때문에 조건 연산자(Conditional Operator)라고 불리기도 합니다.

\n", 9 | "\n", 10 | "```java\n", 11 | "# JAVA식 3항 연산자\n", 12 | "type variable = (condition) ? value when True : value when False;\n", 13 | "# (Is the condition True) ? Yes : No;\n", 14 | "```\n", 15 | "\n", 16 | "조건을 한 줄로 예쁘게 적을 수 있습니다. \n", 17 | "조건, True일 때 return 값, False일 때 return 값으로 3개의 항이 있으므로 3항입니다.\n", 18 | "\n", 19 | "`C`와 `자바`에서 지원합니다. (`?: 연산자`라고도 불립니다.) \n", 20 | "다른 언어보다 적은 코드로 같은 작업을 할 수 있는 것이 장점인 `파이썬`이므로 당연히 지원합니다.\n", 21 | "\n", 22 | "저희가 3항 연산자를 사용해야 하는 이유는 순전히 `가독성(readability)` 때문입니다.\n", 23 | "

카더라로 예전에는 일반 IF-ELSE 조건보다 가벼워서 쓰기 좋다는 말이나 Cyclomatic Complexity가 줄어서 좋다는 말이 있었는데(진위여부는 모릅니다), 현재는 가독성 외에는 큰 의미가 없다고 합니다.

" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "---" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "#### 한 번 보는 단항 연산자와 2항 연산자\n", 38 | "단항 연산자는 항이 1개, 2항 연산자는 항이 2개인게 당연하겠죠?" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 1, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "# 단항 연산자\n", 48 | "a = 1\n", 49 | "b = 2\n", 50 | "b += 2\n", 51 | "# 2항 연산자\n", 52 | "c = 3 + 4" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "---" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "## Python의 3항 연산자\n", 67 | "`Python`은 3항 연산자의 형태가 `C` 혹은 `JAVA`와 매우 다릅니다. \n", 68 | "심지어 `Python`에서는 3가지 방식으로 3항 연산자를 만들 수 있습니다." 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "### 1. and-or 3항 연산자\n", 76 | "```python\n", 77 | "result = condition and value when True or value when False\n", 78 | "```" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 2, 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "name": "stdout", 88 | "output_type": "stream", 89 | "text": [ 90 | "3\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "x = 1\n", 96 | "y = 2\n", 97 | "\n", 98 | "res = x == y and x-y or x+y\n", 99 | "\n", 100 | "print(res) # 기대한대로 a+b인 3이 출력됩니다." 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "metadata": {}, 106 | "source": [ 107 | "보시다시피 `C`와 `자바`의 3항 연산자에서 `?`를 `and`로, `:`를 `or`로 바꿔주면 됩니다.\n", 108 | "\n", 109 | "`?` → `and` \n", 110 | "`:` → `or`\n", 111 | "\n", 112 | "위가 실행되는 이유는 `파이썬`에서 `a and b or c`가 가능하기 때문입니다. 좌측의 연산이 먼저 실행되기 때문에 `(a and b) or c`와 같습니다.\n", 113 | "\n", 114 | "인터프리터는 `a and b`를 우선 확인합니다.\n", 115 | "1. a가 True라면, b를 확인합니다. \n", 116 | " 1. b도 True라면, (a and b)가 True이므로 c를 확인할 것도 없이 b를 return합니다.\n", 117 | " 2. b가 False라면, (a and b)가 False이므로 c를 return합니다.\n", 118 | "2. a가 False라면, a and b가 False이기 때문에 바로 c를 return합니다." 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 3, 124 | "metadata": {}, 125 | "outputs": [ 126 | { 127 | "name": "stdout", 128 | "output_type": "stream", 129 | "text": [ 130 | "2\n" 131 | ] 132 | } 133 | ], 134 | "source": [ 135 | "x = 1\n", 136 | "y = 1\n", 137 | "\n", 138 | "res = x == y and x-y or x+y\n", 139 | "\n", 140 | "print(res) # 기대한대로 x-y인 0이 출력되...지 않는다?" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "`x`와 `y`가 모두 10이기 때문에 `x == y`는 분명 `True`입니다. \n", 148 | "하지만 `x-y`가 아닌 `x+y`가 출력되었습니다.\n", 149 | "\n", 150 | "이 문제는 `a and b or c`에서 `b`가 0일 때 발생합니다. \n", 151 | "컴퓨터는 숫자 0을 `False`로 인식하기 때문에 `b == 0`일 때, `b`는 항상 `False`로 인식합니다. \n", 152 | "`a and 0`는 언제나 `False`가 됩니다.\n", 153 | "\n", 154 | "`파이썬`은 해당 이슈를 여전히 두고 있고, 대신 나중에 새로운 형식의 3항 연산자를 만들었습니다." 155 | ] 156 | }, 157 | { 158 | "cell_type": "markdown", 159 | "metadata": {}, 160 | "source": [ 161 | "### 2. if-else 3항 연산자\n", 162 | "```python\n", 163 | "result = value when True if condition else value when False\n", 164 | "```" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": 4, 170 | "metadata": {}, 171 | "outputs": [ 172 | { 173 | "name": "stdout", 174 | "output_type": "stream", 175 | "text": [ 176 | "3\n" 177 | ] 178 | } 179 | ], 180 | "source": [ 181 | "x = 1\n", 182 | "y = 2\n", 183 | "\n", 184 | "res = x-y if x == y else x+y\n", 185 | "\n", 186 | "print(res) # and-or처럼 x+y가 제대로 출력되었다." 187 | ] 188 | }, 189 | { 190 | "cell_type": "markdown", 191 | "metadata": {}, 192 | "source": [ 193 | "그렇다면 and-or 3항 연산자에서 막힌 부분은 해결되었는지 확인하겠습니다." 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": 5, 199 | "metadata": {}, 200 | "outputs": [ 201 | { 202 | "name": "stdout", 203 | "output_type": "stream", 204 | "text": [ 205 | "0\n" 206 | ] 207 | } 208 | ], 209 | "source": [ 210 | "x = 1\n", 211 | "y = 1\n", 212 | "\n", 213 | "res = x-y if x == y else x+y\n", 214 | "\n", 215 | "print(res) # 기대되로 x-y를 출력했다!" 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "metadata": {}, 221 | "source": [ 222 | "기대대로 `x-y`인 0을 출력했습니다.\n", 223 | "\n", 224 | "둘의 차이는 구조에 있습니다. \n", 225 | "if와 else를 사용한 이번 연산자를 보시면:\n", 226 | "```python\n", 227 | "변수 = True일 때 값 if 조건 else False일 때 값\n", 228 | "```\n", 229 | "위와 같이 구성되어 있습니다. 위를 풀어보면 아래와 같습니다:\n", 230 | "```python\n", 231 | "변수 = 0\n", 232 | "if 조건:\n", 233 | " 변수 = True일 때 값\n", 234 | "else:\n", 235 | " 변수 = False일 때 값\n", 236 | "```\n", 237 | "\n", 238 | "예를 들어, 앞 셀은:" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": 6, 244 | "metadata": {}, 245 | "outputs": [ 246 | { 247 | "name": "stdout", 248 | "output_type": "stream", 249 | "text": [ 250 | "0\n" 251 | ] 252 | } 253 | ], 254 | "source": [ 255 | "x = 1\n", 256 | "y = 1\n", 257 | "res = 0\n", 258 | "\n", 259 | "if x == y:\n", 260 | " res = x - y\n", 261 | "else:\n", 262 | " res = x + y\n", 263 | "\n", 264 | "print(res)" 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": {}, 270 | "source": [ 271 | "위와 같은 형태가 됩니다. 별 것 없으면서 5줄이나 잡아먹는 코드입니다. \n", 272 | "하지만 if-else 3항 연산자를 쓰면 1줄로 줄어듭니다. \n", 273 | "간단한 코드라면 매우 읽기 좋은 형태입니다." 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "### 3. 튜플 3항 연산자\n", 281 | "```python\n", 282 | "result = (value when False, value when True)[something True or False]\n", 283 | "```" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": 7, 289 | "metadata": {}, 290 | "outputs": [ 291 | { 292 | "name": "stdout", 293 | "output_type": "stream", 294 | "text": [ 295 | "I am fat\n" 296 | ] 297 | } 298 | ], 299 | "source": [ 300 | "fat = True\n", 301 | "fitness = (\"skinny\", \"fat\")[fat]\n", 302 | "print(\"I am \", fitness)" 303 | ] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "metadata": {}, 308 | "source": [ 309 | "튜플을 사용한 방법입니다. \n", 310 | "`True`가 1이고 `False`가 0인 것을 이용했습니다. \n", 311 | "튜플의 앞 요소가 `False`일 때 값이고, 뒷 요소가 `True`일 때 값이 됩니다. \n", 312 | "하지만 튜플은 그 자체로 하나의 값이기 때문에 양 요소 모두를 컴퓨터가 인식할 수 있어야 합니다. \n", 313 | "`return`한 값에 에러가 있어도 조건에 부합하지 않으면 확인조차 하지 않는 if 구문과는 다릅니다." 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": 8, 319 | "metadata": {}, 320 | "outputs": [ 321 | { 322 | "ename": "ZeroDivisionError", 323 | "evalue": "division by zero", 324 | "output_type": "error", 325 | "traceback": [ 326 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 327 | "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", 328 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 329 | "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" 330 | ] 331 | } 332 | ], 333 | "source": [ 334 | "(1/0, 2)" 335 | ] 336 | }, 337 | { 338 | "cell_type": "markdown", 339 | "metadata": {}, 340 | "source": [ 341 | "위에 보시다시피 `ZeroDivisionError`가 `raise`되었습니다.\n", 342 | "\n", 343 | "이 상황에서 `(1/0, 2)[True]`나 `(1/0, 2)[False]`는 실행할 수 없습니다." 344 | ] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "execution_count": 9, 349 | "metadata": {}, 350 | "outputs": [ 351 | { 352 | "ename": "ZeroDivisionError", 353 | "evalue": "division by zero", 354 | "output_type": "error", 355 | "traceback": [ 356 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 357 | "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", 358 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 359 | "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" 360 | ] 361 | } 362 | ], 363 | "source": [ 364 | "(1/0, 2)[True]" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": 10, 370 | "metadata": {}, 371 | "outputs": [ 372 | { 373 | "ename": "ZeroDivisionError", 374 | "evalue": "division by zero", 375 | "output_type": "error", 376 | "traceback": [ 377 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 378 | "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", 379 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 380 | "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" 381 | ] 382 | } 383 | ], 384 | "source": [ 385 | "(1/0, 2)[False]" 386 | ] 387 | }, 388 | { 389 | "cell_type": "markdown", 390 | "metadata": {}, 391 | "source": [ 392 | "## 맺음말\n", 393 | "3방법으로 구현한 3항 연산자 중 가장 사용하기 적합한 것은 if-else인 것으로 보입니다. \n", 394 | "구조상 일어날 법한 문제가 없습니다. \n", 395 | "\n", 396 | "그렇지만 if-else에 약점이 없는 것은 아닙니다.\n", 397 | "1. 모든 3항 연산자가 그렇듯이 각 항이 길고 복잡해지면 오히려 가독성이 떨어질 수 있다.\n", 398 | " + 가독성을 위해 쓰는 3항 연산자가 가독성이 떨어지면 안될 일입니다.\n", 399 | "2. if 구문과 달리 break를 쓸 수 없다.\n", 400 | " + while True와 같은 것을 쓰면 끝없이 루프합니다. for를 써도 중간에 끊고 싶어도 끊을 수가 없습니다.\n", 401 | "3. if 구문과 달리 elif를 쓸 수 없다." 402 | ] 403 | }, 404 | { 405 | "cell_type": "markdown", 406 | "metadata": {}, 407 | "source": [ 408 | "### 번외\n", 409 | "마지막으로 if-else 3항 연산자를 썼을 때, 때로는 코드가 너무 길어질 수 있습니다. \n", 410 | "그 경우 가독성을 보장하기 위해 `break line`을 넣어보겠습니다." 411 | ] 412 | }, 413 | { 414 | "cell_type": "code", 415 | "execution_count": 11, 416 | "metadata": {}, 417 | "outputs": [ 418 | { 419 | "name": "stdout", 420 | "output_type": "stream", 421 | "text": [ 422 | "I'd love that!\n" 423 | ] 424 | } 425 | ], 426 | "source": [ 427 | "a = \"I'd love that!\"\n", 428 | "b = \"Nope!\"\n", 429 | "x = True\n", 430 | "\n", 431 | "# 문제없다!\n", 432 | "res = a if x is True else b\n", 433 | "print(res)" 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": 12, 439 | "metadata": {}, 440 | "outputs": [ 441 | { 442 | "ename": "SyntaxError", 443 | "evalue": "invalid syntax (, line 2)", 444 | "output_type": "error", 445 | "traceback": [ 446 | "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m2\u001b[0m\n\u001b[1;33m res = a if x is True\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" 447 | ] 448 | } 449 | ], 450 | "source": [ 451 | "# SyntaxError\n", 452 | "res = a if x is True\n", 453 | "else b" 454 | ] 455 | }, 456 | { 457 | "cell_type": "code", 458 | "execution_count": 13, 459 | "metadata": {}, 460 | "outputs": [ 461 | { 462 | "name": "stdout", 463 | "output_type": "stream", 464 | "text": [ 465 | "I'd love that!\n" 466 | ] 467 | } 468 | ], 469 | "source": [ 470 | "res = (\n", 471 | " a if x is True\n", 472 | " else b)\n", 473 | "print(res)" 474 | ] 475 | }, 476 | { 477 | "cell_type": "code", 478 | "execution_count": 14, 479 | "metadata": {}, 480 | "outputs": [ 481 | { 482 | "name": "stdout", 483 | "output_type": "stream", 484 | "text": [ 485 | "I'd love that!\n" 486 | ] 487 | } 488 | ], 489 | "source": [ 490 | "res = (a if\n", 491 | " x is True else b)\n", 492 | "print(res)" 493 | ] 494 | }, 495 | { 496 | "cell_type": "code", 497 | "execution_count": 15, 498 | "metadata": {}, 499 | "outputs": [ 500 | { 501 | "name": "stdout", 502 | "output_type": "stream", 503 | "text": [ 504 | "I'd love that!\n" 505 | ] 506 | } 507 | ], 508 | "source": [ 509 | "res = (a if x is True else\n", 510 | " b)\n", 511 | "print(res)" 512 | ] 513 | }, 514 | { 515 | "cell_type": "markdown", 516 | "metadata": {}, 517 | "source": [ 518 | "이렇게 괄호 `()` 안에 가두는 것을 `implicit line joining`이라고 합니다. \n", 519 | "열린 괄호가 닫힐 때까지 안을 모두 하나로 인식하기 때문에 줄을 바꿔도 문제없이 인식합니다. \n", 520 | "하지만 indentation은 조심해주세요. \n", 521 | "\n", 522 | "보기 안 좋거든요." 523 | ] 524 | }, 525 | { 526 | "cell_type": "code", 527 | "execution_count": null, 528 | "metadata": {}, 529 | "outputs": [], 530 | "source": [] 531 | } 532 | ], 533 | "metadata": { 534 | "kernelspec": { 535 | "display_name": "Python 3", 536 | "language": "python", 537 | "name": "python3" 538 | }, 539 | "language_info": { 540 | "codemirror_mode": { 541 | "name": "ipython", 542 | "version": 3 543 | }, 544 | "file_extension": ".py", 545 | "mimetype": "text/x-python", 546 | "name": "python", 547 | "nbconvert_exporter": "python", 548 | "pygments_lexer": "ipython3", 549 | "version": "3.7.3" 550 | } 551 | }, 552 | "nbformat": 4, 553 | "nbformat_minor": 2 554 | } 555 | -------------------------------------------------------------------------------- /day3/10_lambda_time.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 18, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import time" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 7, 17 | "metadata": { 18 | "collapsed": false 19 | }, 20 | "outputs": [], 21 | "source": [ 22 | "# Method.\n", 23 | "def square1(n):\n", 24 | " return n ** 2\n", 25 | "\n", 26 | "# Lambda method.\n", 27 | "square2 = lambda n: n ** 2" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": { 34 | "collapsed": false 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "# Use def method.\n", 39 | "start_time = time.time() \n", 40 | "\n", 41 | "i = 0\n", 42 | "while i < 100000000:\n", 43 | " square1(i)\n", 44 | " i += 1\n", 45 | "\n", 46 | "print(\"--- %s seconds ---\" %(time.time() - start_time))" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": { 53 | "collapsed": false 54 | }, 55 | "outputs": [], 56 | "source": [ 57 | "# Use lambda method.\n", 58 | "start_time = time.time() \n", 59 | "i = 0\n", 60 | "while i < 100000000:\n", 61 | " square2(i)\n", 62 | " i += 1\n", 63 | "\n", 64 | "print(\"--- %s seconds ---\" %(time.time() - start_time))" 65 | ] 66 | } 67 | ], 68 | "metadata": { 69 | "kernelspec": { 70 | "display_name": "Python 3", 71 | "language": "python", 72 | "name": "python3" 73 | }, 74 | "language_info": { 75 | "codemirror_mode": { 76 | "name": "ipython", 77 | "version": 3 78 | }, 79 | "file_extension": ".py", 80 | "mimetype": "text/x-python", 81 | "name": "python", 82 | "nbconvert_exporter": "python", 83 | "pygments_lexer": "ipython3", 84 | "version": "3.5.1rc1" 85 | } 86 | }, 87 | "nbformat": 4, 88 | "nbformat_minor": 2 89 | } 90 | -------------------------------------------------------------------------------- /day3/11_Comprehension.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Python Comprehension\n", 8 | "### 한 sequence가 다른 sequence(iterable object)로부터 변형되어 구축될 수 있게한 기능\n", 9 | "### iterable한 오브젝트를 생성하기 위한 방법중 하나로 파이썬에서 사용할 수 있는 유용한 기능중 하나\n", 10 | "* Python2 : List Comprehension 만 지원\n", 11 | "* Python3 : Dictionary Comprehension과 Set Comprehension추가 지원\n", 12 | "* Generator Comprehension이라 일컫는 Generator Expression" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "### List Comprehension" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 10, 32 | "metadata": {}, 33 | "outputs": [ 34 | { 35 | "name": "stdout", 36 | "output_type": "stream", 37 | "text": [ 38 | "[0, 9, 36, 81, 144, 225, 324, 441, 576, 729, 900, 1089, 1296, 1521, 1764, 2025, 2304]\n" 39 | ] 40 | } 41 | ], 42 | "source": [ 43 | "num = [x**2 for x in range(0,50) if x % 3 ==0]\n", 44 | "print(num)" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "### Dictionary Comprehension" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "##### 두 리스트를 하나의 dict로 합치는 DC. 하나는 key, 또 다른 하나는 value로 사용한다" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": null, 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "subjects = ['math', 'history', 'english', 'computer engineering']\n", 68 | "scores = [90, 80, 95, 100]\n", 69 | "score_dict = {key: value for key, value in zip(subjects, scores)}\n", 70 | "print(score_dict)" 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "##### 튜플 리스트를 dict 형태로 변환하는 DC" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 4, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "name": "stdout", 87 | "output_type": "stream", 88 | "text": [ 89 | "{'math': 90, 'history': 80, 'english': 95, 'computer engineering': 100}\n" 90 | ] 91 | } 92 | ], 93 | "source": [ 94 | "score_tuples = [('math', 90), ('history', 80), ('english', 95), ('computer engineering', 100)]\n", 95 | "score_dict2 = {t[0]: t[1] for t in score_tuples}\n", 96 | "print(score_dict2)" 97 | ] 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "metadata": {}, 102 | "source": [ 103 | "### Set Comprehension" 104 | ] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": {}, 109 | "source": [ 110 | "##### 다음의 LC는 중복된 값들을 포함한다" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 5, 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "name": "stdout", 120 | "output_type": "stream", 121 | "text": [ 122 | "[4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 10, 15, 20, 25, 30, 35, 40, 45, 12, 18, 24, 30, 36, 42, 48, 14, 21, 28, 35, 42, 49, 16, 24, 32, 40, 48]\n" 123 | ] 124 | } 125 | ], 126 | "source": [ 127 | "no_primes = [j for i in range(2, 9) for j in range(i * 2, 50, i)]\n", 128 | "print(no_primes)" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | "##### SC를 사용하면 중복값이 없는 집합을 얻을 수 있다" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 6, 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "name": "stdout", 145 | "output_type": "stream", 146 | "text": [ 147 | "{4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46, 48, 49}\n" 148 | ] 149 | } 150 | ], 151 | "source": [ 152 | "no_primes2 = {j for i in range(2, 9) for j in range(i * 2, 50, i)}\n", 153 | "print(no_primes2)" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "### Reference\n", 161 | "* http://www.thagomizer.com/blog/2018/03/21/a-rubyist-learns-list-comprehensions.html\n", 162 | "* https://mingrammer.com/introduce-comprehension-of-python/" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [] 171 | } 172 | ], 173 | "metadata": { 174 | "kernelspec": { 175 | "display_name": "Python 3", 176 | "language": "python", 177 | "name": "python3" 178 | }, 179 | "language_info": { 180 | "codemirror_mode": { 181 | "name": "ipython", 182 | "version": 3 183 | }, 184 | "file_extension": ".py", 185 | "mimetype": "text/x-python", 186 | "name": "python", 187 | "nbconvert_exporter": "python", 188 | "pygments_lexer": "ipython3", 189 | "version": "3.6.1" 190 | } 191 | }, 192 | "nbformat": 4, 193 | "nbformat_minor": 2 194 | } 195 | -------------------------------------------------------------------------------- /day3/12_For-else.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## For-else" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "* 보통의 프로그래밍언어에서 'else'라고하면, if와 함께 오는 경우가 대부분이지만, 파이썬에서는 for문과 함께 쓰기도합니다.\n", 15 | "* for-else는 for문이 중간에 break등으로 끊기지않고, 끝까지 수행되었을때 수행되는 코드를 담고있습니다.\n", 16 | "* 코딩을 하다보면 for문이 중간에 break되었는지, 되어있지 않는지 판별할때 테스트 변수를둬서 확인하는 방법으로 처리합니다. 이를 파이썬에서는 For-else문으로 간단하게 해결할수있습니다.\n" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "metadata": {}, 23 | "outputs": [ 24 | { 25 | "name": "stdout", 26 | "output_type": "stream", 27 | "text": [ 28 | "4 = 2 * 2.0\n", 29 | "6 = 2 * 3.0\n", 30 | "8 = 2 * 4.0\n", 31 | "9 = 3 * 3.0\n" 32 | ] 33 | } 34 | ], 35 | "source": [ 36 | "for n in range(2, 10):\n", 37 | " for x in range(2, n):\n", 38 | " if n % x == 0:\n", 39 | " print (n, '=', x, '*', n/x)\n", 40 | " break" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 2, 46 | "metadata": {}, 47 | "outputs": [ 48 | { 49 | "name": "stdout", 50 | "output_type": "stream", 51 | "text": [ 52 | "2 은 소수입니다.\n", 53 | "3 은 소수입니다.\n", 54 | "4 = 2 * 2.0\n", 55 | "5 은 소수입니다.\n", 56 | "6 = 2 * 3.0\n", 57 | "7 은 소수입니다.\n", 58 | "8 = 2 * 4.0\n", 59 | "9 = 3 * 3.0\n" 60 | ] 61 | } 62 | ], 63 | "source": [ 64 | "for n in range(2, 10):\n", 65 | " for x in range(2, n):\n", 66 | " if n % x == 0:\n", 67 | " print (n, '=', x, '*', n/x)\n", 68 | " break\n", 69 | " else:\n", 70 | " # 루프가 끝나고 요소를 못 찾았을 때 \n", 71 | " print (n, '은 소수입니다.')" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "### Reference\n", 79 | "https://harryp.tistory.com/317" 80 | ] 81 | } 82 | ], 83 | "metadata": { 84 | "kernelspec": { 85 | "display_name": "Python 3", 86 | "language": "python", 87 | "name": "python3" 88 | }, 89 | "language_info": { 90 | "codemirror_mode": { 91 | "name": "ipython", 92 | "version": 3 93 | }, 94 | "file_extension": ".py", 95 | "mimetype": "text/x-python", 96 | "name": "python", 97 | "nbconvert_exporter": "python", 98 | "pygments_lexer": "ipython3", 99 | "version": "3.6.1" 100 | } 101 | }, 102 | "nbformat": 4, 103 | "nbformat_minor": 2 104 | } 105 | -------------------------------------------------------------------------------- /day3/13_enumerate.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# enumerate\n", 8 | "- 파이썬의 내장함수\n", 9 | "- 순서가 있는 자료형(리스트, 튜플, 문자열)을 입력으로 받아 인덱스 값을 포함하는 enumerate 객체를 리턴.\n", 10 | "- 보통 enumerate 함수는 for문과 함께 자주 사용.\n", 11 | "- for문처럼 반복되는 구간에서 객체가 현재 어느 위치에 있는지 알려주는 인덱스 값이 필요할때 enumerate 함수를 사용하면 매우 유용." 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 20, 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "name": "stdout", 21 | "output_type": "stream", 22 | "text": [ 23 | "list is iterable : True\n", 24 | "dict is iterable : True\n", 25 | "set is iterable : True\n", 26 | "string is iterable : True\n", 27 | "bytes is iterable : True\n", 28 | "tuple is iterable : True\n", 29 | "range is iterable : True\n", 30 | "--------------------------------------------------\n", 31 | "int is iterable : False\n", 32 | "float is iterable : False\n", 33 | "None is iterable : False\n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "import collections\n", 39 | "\n", 40 | "# iterable 한 타입\n", 41 | "var_list = [1, 3, 5, 7]\n", 42 | "print(\"list is iterable : \", isinstance(var_list, collections.Iterable))\n", 43 | "\n", 44 | "var_dict = {\"a\": 1, \"b\":1}\n", 45 | "print(\"dict is iterable : \", isinstance(var_dict, collections.Iterable))\n", 46 | "\n", 47 | "var_set = {1, 3}\n", 48 | "print(\"set is iterable : \", isinstance(var_set, collections.Iterable))\n", 49 | "\n", 50 | "var_str = \"abc\"\n", 51 | "print(\"string is iterable : \", isinstance(var_str, collections.Iterable))\n", 52 | "\n", 53 | "var_bytes = b'abcdef'\n", 54 | "print(\"bytes is iterable : \", isinstance(var_bytes, collections.Iterable))\n", 55 | "\n", 56 | "var_tuple = (1, 3, 5, 7)\n", 57 | "print(\"tuple is iterable : \", isinstance(var_tuple, collections.Iterable))\n", 58 | "\n", 59 | "var_range = range(0,5)\n", 60 | "print(\"range is iterable : \", isinstance(var_range, collections.Iterable))\n", 61 | "print(\"-\" * 50)\n", 62 | "var_int = 932\n", 63 | "print(\"int is iterable : \", isinstance(var_int, collections.Iterable))\n", 64 | "\n", 65 | "var_float = 10.2\n", 66 | "print(\"float is iterable : \", isinstance(var_float, collections.Iterable))\n", 67 | "\n", 68 | "var_none = None\n", 69 | "print(\"None is iterable : \", isinstance(var_none, collections.Iterable))\n" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "my_list = ['body', 'foo', 'bar']" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 12, 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "name": "stdout", 88 | "output_type": "stream", 89 | "text": [ 90 | "0 사과\n", 91 | "1 바나나\n", 92 | "2 포도\n", 93 | "3 배\n" 94 | ] 95 | } 96 | ], 97 | "source": [ 98 | "# range 이용\n", 99 | "for i in range(len(my_list)):\n", 100 | " item = my_list[i]\n", 101 | " print(i, item)" 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 22, 107 | "metadata": {}, 108 | "outputs": [ 109 | { 110 | "data": { 111 | "text/plain": [ 112 | "True" 113 | ] 114 | }, 115 | "execution_count": 22, 116 | "metadata": {}, 117 | "output_type": "execute_result" 118 | } 119 | ], 120 | "source": [ 121 | "isinstance(enumerate(my_list), collections.Iterable)" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 7, 127 | "metadata": {}, 128 | "outputs": [ 129 | { 130 | "name": "stdout", 131 | "output_type": "stream", 132 | "text": [ 133 | "0 사과\n", 134 | "1 바나나\n", 135 | "2 포도\n", 136 | "3 배\n" 137 | ] 138 | } 139 | ], 140 | "source": [ 141 | "for i, name in enumerate(my_list):\n", 142 | " print(i, name)" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "- optional argument를 이용가능함" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 8, 155 | "metadata": {}, 156 | "outputs": [ 157 | { 158 | "name": "stdout", 159 | "output_type": "stream", 160 | "text": [ 161 | "1 사과\n", 162 | "2 바나나\n", 163 | "3 포도\n", 164 | "4 배\n" 165 | ] 166 | } 167 | ], 168 | "source": [ 169 | "for c, value in enumerate(my_list, 1):\n", 170 | " print (c, value)" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": 25, 176 | "metadata": {}, 177 | "outputs": [], 178 | "source": [ 179 | "def my_enumerate(sequence, start=0):\n", 180 | " n = start\n", 181 | " for elem in sequence:\n", 182 | " yield n, elem\n", 183 | " n += 1" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 24, 189 | "metadata": {}, 190 | "outputs": [ 191 | { 192 | "name": "stdout", 193 | "output_type": "stream", 194 | "text": [ 195 | "1 사과\n", 196 | "2 바나나\n", 197 | "3 포도\n", 198 | "4 배\n" 199 | ] 200 | } 201 | ], 202 | "source": [ 203 | "for c, value in my_enumerate(my_list, 1):\n", 204 | " print (c, value)" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "metadata": {}, 210 | "source": [ 211 | "- optional argument를 이용하여 인덱스를 포함하는 튜플 만들기" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 9, 217 | "metadata": {}, 218 | "outputs": [ 219 | { 220 | "name": "stdout", 221 | "output_type": "stream", 222 | "text": [ 223 | "[(1, '사과'), (2, '바나나'), (3, '포도'), (4, '배')]\n" 224 | ] 225 | } 226 | ], 227 | "source": [ 228 | "my_list = ['사과', '바나나', '포도', '배']\n", 229 | "counter_list = list(enumerate(my_list, 1))\n", 230 | "print(counter_list)" 231 | ] 232 | } 233 | ], 234 | "metadata": { 235 | "kernelspec": { 236 | "display_name": "Python 3", 237 | "language": "python", 238 | "name": "python3" 239 | }, 240 | "language_info": { 241 | "codemirror_mode": { 242 | "name": "ipython", 243 | "version": 3 244 | }, 245 | "file_extension": ".py", 246 | "mimetype": "text/x-python", 247 | "name": "python", 248 | "nbconvert_exporter": "python", 249 | "pygments_lexer": "ipython3", 250 | "version": "3.6.7" 251 | } 252 | }, 253 | "nbformat": 4, 254 | "nbformat_minor": 2 255 | } 256 | -------------------------------------------------------------------------------- /day3/14___slots__.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# \\_\\_slots\\_\\_\n", 8 | "\n", 9 | "- 파이썬은 인스턴스의 모든 속성을 dict에 동적 저장\n", 10 | "- \\_\\_slots\\_\\_ 명령어를 통해 속성을 정적 정의 가능\n", 11 | "- 장점: 속성 정의/호출 속도 향상 및 메모리 사용량 감소\n", 12 | "- 단점: 정의 이후 속성 추가/제거 불가" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "참고:\n", 20 | "1. https://www.christianbarra.com/posts/let-me-introduce-slots/\n", 21 | "2. https://blog.usejournal.com/a-quick-dive-into-pythons-slots-72cdc2d334e7\n", 22 | "3. https://thomas-cokelaer.info/tutorials/python/slots.html" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "## 사용 예시\n", 30 | "\\_\\_init\\_\\_ 함수 전에 \\_\\_slots\\_\\_ = [] 형태로 정의" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 1, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "class MyClass(object):\n", 40 | " __slots__ = ['name', 'identifier']\n", 41 | " def __init__(self, name, identifier):\n", 42 | " self.name = name\n", 43 | " self.identifier = identifier\n", 44 | " self.set_up()" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 2, 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "name": "stdout", 54 | "output_type": "stream", 55 | "text": [ 56 | "In [2] used 0.0000 MiB RAM in 0.10s, peaked 0.00 MiB above current, total RAM usage 60.49 MiB\n" 57 | ] 58 | } 59 | ], 60 | "source": [ 61 | "import ipython_memory_usage.ipython_memory_usage as imu\n", 62 | "num = 1024*256\n", 63 | "imu.start_watching_memory()" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "## 메모리 사용량 및 속도 비교" 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "\\_\\_slots\\_\\_: MyClass1" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 3, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "name": "stdout", 87 | "output_type": "stream", 88 | "text": [ 89 | "In [3] used 0.0938 MiB RAM in 0.10s, peaked 0.00 MiB above current, total RAM usage 60.58 MiB\n" 90 | ] 91 | } 92 | ], 93 | "source": [ 94 | "class MyClass1(object):\n", 95 | " __slots__ = ['name', 'identifier']\n", 96 | " def __init__(self, name, identifier):\n", 97 | " self.name = name\n", 98 | " self.identifier = identifier\n", 99 | "\n", 100 | "class MyClass2(object):\n", 101 | " def __init__(self, name, identifier):\n", 102 | " self.name = name\n", 103 | " self.identifier = identifier" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 4, 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "name": "stdout", 113 | "output_type": "stream", 114 | "text": [ 115 | "162 ms ± 2.35 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", 116 | "214 ms ± 4.56 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", 117 | "In [4] used 2.5039 MiB RAM in 14.99s, peaked 41.80 MiB above current, total RAM usage 63.09 MiB\n" 118 | ] 119 | } 120 | ], 121 | "source": [ 122 | "%timeit [MyClass1(1,1) for i in range(num)]\n", 123 | "%timeit [MyClass2(1,1) for i in range(num)]" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 5, 129 | "metadata": {}, 130 | "outputs": [ 131 | { 132 | "name": "stdout", 133 | "output_type": "stream", 134 | "text": [ 135 | "In [5] used 15.6836 MiB RAM in 0.40s, peaked 0.00 MiB above current, total RAM usage 78.77 MiB\n" 136 | ] 137 | } 138 | ], 139 | "source": [ 140 | "x = [MyClass1(1,1) for i in range(num)]" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 6, 146 | "metadata": {}, 147 | "outputs": [ 148 | { 149 | "name": "stdout", 150 | "output_type": "stream", 151 | "text": [ 152 | "In [6] used 44.6758 MiB RAM in 0.44s, peaked 0.00 MiB above current, total RAM usage 123.45 MiB\n" 153 | ] 154 | } 155 | ], 156 | "source": [ 157 | "y = [MyClass2(1,1) for i in range(num)]" 158 | ] 159 | }, 160 | { 161 | "cell_type": "markdown", 162 | "metadata": {}, 163 | "source": [ 164 | "### 사이즈 비교" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": 7, 170 | "metadata": {}, 171 | "outputs": [ 172 | { 173 | "name": "stdout", 174 | "output_type": "stream", 175 | "text": [ 176 | "80 112\n", 177 | "In [7] used -0.0078 MiB RAM in 0.10s, peaked 0.01 MiB above current, total RAM usage 123.44 MiB\n" 178 | ] 179 | } 180 | ], 181 | "source": [ 182 | "from sys import getsizeof\n", 183 | "print(getsizeof(x[0].__slots__), getsizeof(y[0].__dict__))" 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "metadata": {}, 189 | "source": [ 190 | "## 속성을 추가하고 싶을 땐?" 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": 8, 196 | "metadata": {}, 197 | "outputs": [ 198 | { 199 | "ename": "AttributeError", 200 | "evalue": "'MyClass1' object has no attribute 'test_value'", 201 | "output_type": "error", 202 | "traceback": [ 203 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 204 | "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", 205 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtest_value\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m'Some String'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 206 | "\u001b[1;31mAttributeError\u001b[0m: 'MyClass1' object has no attribute 'test_value'" 207 | ] 208 | }, 209 | { 210 | "name": "stdout", 211 | "output_type": "stream", 212 | "text": [ 213 | "In [8] used 0.6094 MiB RAM in 0.22s, peaked 0.00 MiB above current, total RAM usage 124.05 MiB\n" 214 | ] 215 | } 216 | ], 217 | "source": [ 218 | "x[0].test_value = 'Some String'" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": 5, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "class MyClass3(object):\n", 228 | " __slots__ = ['name', 'identifier', '__dict__']\n", 229 | " def __init__(self, name):\n", 230 | " self.name = name\n", 231 | " self.identifier = identifier" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": 10, 237 | "metadata": {}, 238 | "outputs": [ 239 | { 240 | "name": "stdout", 241 | "output_type": "stream", 242 | "text": [ 243 | "167 ms ± 2.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", 244 | "213 ms ± 2.22 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", 245 | "In [10] used -0.8867 MiB RAM in 15.40s, peaked 42.64 MiB above current, total RAM usage 123.18 MiB\n" 246 | ] 247 | } 248 | ], 249 | "source": [ 250 | "%timeit [MyClass3(1,1) for i in range(num)]\n", 251 | "%timeit [MyClass2(1,1) for i in range(num)]" 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": 11, 257 | "metadata": {}, 258 | "outputs": [ 259 | { 260 | "name": "stdout", 261 | "output_type": "stream", 262 | "text": [ 263 | "In [11] used 18.9727 MiB RAM in 0.46s, peaked 0.00 MiB above current, total RAM usage 142.15 MiB\n" 264 | ] 265 | } 266 | ], 267 | "source": [ 268 | "z = [MyClass3(1,1) for i in range(num)]" 269 | ] 270 | }, 271 | { 272 | "cell_type": "code", 273 | "execution_count": 12, 274 | "metadata": {}, 275 | "outputs": [ 276 | { 277 | "name": "stdout", 278 | "output_type": "stream", 279 | "text": [ 280 | "In [12] used 44.6992 MiB RAM in 0.43s, peaked 0.00 MiB above current, total RAM usage 186.85 MiB\n" 281 | ] 282 | } 283 | ], 284 | "source": [ 285 | "a = [MyClass2(1,1) for i in range(num)]" 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": 13, 291 | "metadata": {}, 292 | "outputs": [ 293 | { 294 | "name": "stdout", 295 | "output_type": "stream", 296 | "text": [ 297 | "1 1 {'test_value': 'Some String'} Some String\n", 298 | "In [13] used -1.5156 MiB RAM in 0.10s, peaked 1.52 MiB above current, total RAM usage 185.34 MiB\n" 299 | ] 300 | } 301 | ], 302 | "source": [ 303 | "a[0].test_value = 'Some String'\n", 304 | "z[0].test_value = 'Some String'\n", 305 | "print(z[0].name, z[0].identifier, z[0].__dict__, z[0].test_value)" 306 | ] 307 | }, 308 | { 309 | "cell_type": "code", 310 | "execution_count": 14, 311 | "metadata": {}, 312 | "outputs": [ 313 | { 314 | "name": "stdout", 315 | "output_type": "stream", 316 | "text": [ 317 | "88 112 112\n", 318 | "In [14] used 0.0000 MiB RAM in 0.11s, peaked 0.00 MiB above current, total RAM usage 185.34 MiB\n" 319 | ] 320 | } 321 | ], 322 | "source": [ 323 | "print(getsizeof(z[0].__slots__), getsizeof(z[0].__dict__), getsizeof(a[0].__dict__))" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": null, 329 | "metadata": {}, 330 | "outputs": [], 331 | "source": [] 332 | } 333 | ], 334 | "metadata": { 335 | "kernelspec": { 336 | "display_name": "Python 3", 337 | "language": "python", 338 | "name": "python3" 339 | }, 340 | "language_info": { 341 | "codemirror_mode": { 342 | "name": "ipython", 343 | "version": 3 344 | }, 345 | "file_extension": ".py", 346 | "mimetype": "text/x-python", 347 | "name": "python", 348 | "nbconvert_exporter": "python", 349 | "pygments_lexer": "ipython3", 350 | "version": "3.6.8" 351 | } 352 | }, 353 | "nbformat": 4, 354 | "nbformat_minor": 2 355 | } 356 | -------------------------------------------------------------------------------- /day4/16_virtualenv.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "slideshow": { 7 | "slide_type": "slide" 8 | } 9 | }, 10 | "source": [ 11 | "# Virtual Environment" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": { 17 | "slideshow": { 18 | "slide_type": "slide" 19 | } 20 | }, 21 | "source": [ 22 | "##### pip install\n", 23 | "- pip를 통해 third-party 라이브러리를 설치하면 글로벌하게 설치된다.\n", 24 | "- 설치된 라이브러리는 파이썬 설치폴더 하위에 위치한 site-packages(혹은 dist-packages) 폴더 안에 위치한다." 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "slideshow": { 31 | "slide_type": "subslide" 32 | } 33 | }, 34 | "source": [ 35 | "##### 라이브러리가 위치한 폴더 예제\n", 36 | "- /usr/local/lib/python2.7/site-packages\n", 37 | "- /usr/local/lib/python3.6/dist-packages\n", 38 | "- C:\\Python37\\Lib\\site-packages" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": { 44 | "slideshow": { 45 | "slide_type": "subslide" 46 | } 47 | }, 48 | "source": [ 49 | "##### 여러 버전의 라이브러리 설치할 수 있는가?\n", 50 | "- 동일한 라이브러리의 여러 버전을 동시에 설치할 수 없다. \n", 51 | "- 가령 requests 2.22, requests 2.18.4 을 동시에 설치할 수 없다." 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": { 57 | "slideshow": { 58 | "slide_type": "slide" 59 | } 60 | }, 61 | "source": [ 62 | "----------------------------\n", 63 | "## 가상환경이 필요한 경우는?\n", 64 | "\n", 65 | "##### 1. 한대의 개발 PC에서 두개 이상의 프로젝트를 수행하는데, 서로 다른 버전의 라이브러리를 사용해야 할 때\n", 66 | "\n", 67 | "\n", 68 | "- A프로젝트 : requests 2.22\n", 69 | "- B프로젝트 : requests 2.18.4\n", 70 | "\n", 71 | "\n", 72 | "- 하지만 가상환경을 사용하면, 각각의 독립된 가상환경 위에 라이브러리를 설치할 수 있다.\n", 73 | "- 따라서 서로 다른 가상환경에서 서로 다른 버전의 라이브러리를 설치할 수 있다." 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": { 79 | "slideshow": { 80 | "slide_type": "subslide" 81 | } 82 | }, 83 | "source": [ 84 | "##### 2. 배포의 일관성\n", 85 | "\n", 86 | "\n", 87 | "- 프로젝트별로 다른 가상환경을 만들면 추후 프로젝트를 배포시 환경 전체를 압축해서 배포하는 것이 가능하다.\n", 88 | "\n" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": { 94 | "slideshow": { 95 | "slide_type": "slide" 96 | } 97 | }, 98 | "source": [ 99 | "----------------------------\n", 100 | "## 가상환경\n", 101 | "- 독립된 파이썬 환경을 생성하는 도구이다.\n", 102 | "- 파이썬과 원하는 모듈만 담아 운용하는 독립된 공간 정도로 생각하면 된다.\n", 103 | "- 의존성과 버전 문제 차이로 인한 어플리케이션간 충돌 문제를 해결할 수 있다." 104 | ] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": { 109 | "slideshow": { 110 | "slide_type": "slide" 111 | } 112 | }, 113 | "source": [ 114 | "----------------------------\n", 115 | "## 가상환경을 지원하는 라이브러리\n", 116 | "\n", 117 | "##### 1. venv\n", 118 | "파이썬 3에 내장\n", 119 | "\n", 120 | "##### 2. pyenv\n", 121 | "https://github.com/pyenv/pyenv\n", 122 | "\n", 123 | "##### 3. virtualenv\n", 124 | "- 2017년 현재 가장 널리 사용되고 있는 도구\n", 125 | "- https://pypi.org/project/virtualenv/\n", 126 | "\n", 127 | "##### 4. virtualenvwrapper\n", 128 | "가상환경의 생성, 삭제, 프로젝트 이동, 관리 등을 좀 더 쉽게 할 수 있도록 virtualenv의 확장툴" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": { 134 | "slideshow": { 135 | "slide_type": "slide" 136 | } 137 | }, 138 | "source": [ 139 | "----------------------------\n", 140 | "## venv\n", 141 | "\n", 142 | "##### 설치 \n", 143 | "```\n", 144 | "> apt install python3-venv\n", 145 | "```\n", 146 | "\n", 147 | "##### 가상환경 만들기 \n", 148 | "\n", 149 | "```\n", 150 | "> python3 -m venv 가상환경이름\n", 151 | "```\n", 152 | "\n", 153 | "##### 가상환경 진입하기\n", 154 | "\n", 155 | "```\n", 156 | "> source ./가상환경이름/bin/activate\n", 157 | "```\n", 158 | "\n", 159 | "\n", 160 | "##### 가상환경 나오기\n", 161 | "\n", 162 | "```\n", 163 | "> deactivate\n", 164 | "```" 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": { 170 | "slideshow": { 171 | "slide_type": "subslide" 172 | } 173 | }, 174 | "source": [ 175 | "##### pip freeze\n", 176 | "\n", 177 | "- pip freeze 는 설치된 패키지의 비슷한 목록을 만들지만, pip install 이 기대하는 형식을 사용한다.\n", 178 | "- 일반적인 규칙은 이 목록을 requirements.txt 파일에 넣어 배포한다.\n", 179 | "\n", 180 | "```\n", 181 | "> pip freeze > requirements.txt\n", 182 | "```\n", 183 | "\n", 184 | "- 사용자는 install -r 로 모든 필요한 패키지를 설치할 수 있다.\n", 185 | "\n", 186 | "```\n", 187 | "> pip install -r requirements.txt\n", 188 | "```" 189 | ] 190 | }, 191 | { 192 | "cell_type": "markdown", 193 | "metadata": { 194 | "slideshow": { 195 | "slide_type": "slide" 196 | } 197 | }, 198 | "source": [ 199 | "----------------------------\n", 200 | "## virtualenv\n", 201 | "\n", 202 | "##### 설치 \n", 203 | "```\n", 204 | "> pip3 install virtualenv\n", 205 | "```\n", 206 | "\n", 207 | "##### 가상환경 만들기 \n", 208 | "\n", 209 | "```\n", 210 | "> virtualenv 가상환경이름\n", 211 | "```\n", 212 | "\n", 213 | "##### 가상환경 만들기(파이썬 버전 설정)\n", 214 | "\n", 215 | "```\n", 216 | "> virtualenv --python=python2.7 가상환경이름\n", 217 | "```\n", 218 | "\n", 219 | "##### 가상환경 진입하기\n", 220 | "\n", 221 | "```\n", 222 | "> source ./가상환경이름/bin/activate\n", 223 | "```\n", 224 | "\n", 225 | "##### 가상환경 나오기\n", 226 | "\n", 227 | "```\n", 228 | "> deactivate\n", 229 | "```" 230 | ] 231 | }, 232 | { 233 | "cell_type": "markdown", 234 | "metadata": { 235 | "slideshow": { 236 | "slide_type": "subslide" 237 | } 238 | }, 239 | "source": [ 240 | "----------------------------\n", 241 | "## venv, virtualenv의 불편함\n", 242 | "\n", 243 | "- 가상환경에 진입할 때 프로젝트 경로를 알아야 한다.\n", 244 | "- 다른 가상환경으로 이동하려면 deactivate 후 이동해야 한다." 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": { 250 | "slideshow": { 251 | "slide_type": "slide" 252 | } 253 | }, 254 | "source": [ 255 | "----------------------------\n", 256 | "## virtualenvwrapper \n", 257 | "\n", 258 | "##### 설치 \n", 259 | "```\n", 260 | "> pip3 install virtualenvwrapper\n", 261 | "```\n", 262 | "\n", 263 | "##### virtualenvwrapper 실행\n", 264 | "```\n", 265 | "> source /usr/local/bin/virtualenvwrapper.sh\n", 266 | "```" 267 | ] 268 | }, 269 | { 270 | "cell_type": "markdown", 271 | "metadata": { 272 | "slideshow": { 273 | "slide_type": "subslide" 274 | } 275 | }, 276 | "source": [ 277 | "##### 필요한 설정\n", 278 | "\n", 279 | "- 두개의 환경 변수를 설정한다.\n", 280 | "```\n", 281 | "> export WORKON_HOME='가상환경이 위치할 폴더' \n", 282 | "(기본값=$HOME/.virtualenvs)\n", 283 | "> export VIRTUALENVWRAPPER_PYTHON='파이썬 경로'\n", 284 | "```\n", 285 | "\n", 286 | "- 예를 들어\n", 287 | "```\n", 288 | "> export WORKON_HOME=~/envs\n", 289 | "> export VIRTUALENVWRAPPER_PYTHON='/usr/bin/python3'\n", 290 | "```\n", 291 | "\n", 292 | "- 파이썬 위치를 찾으려면?\n", 293 | "```\n", 294 | "> which python3\n", 295 | "/usr/bin/python3\n", 296 | "```" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "metadata": { 302 | "slideshow": { 303 | "slide_type": "subslide" 304 | } 305 | }, 306 | "source": [ 307 | "##### 자동 실행 설정\n", 308 | "- 터미널을 재 시작하면 두개의 환경변수를 다시 설정해야 하고 virtualenvwrapper.sh를 다시 실행해야 한다.\n", 309 | "- home 디렉토리에 .bashrc나 .bash_profile의 마지막에 다음 3줄을 추가하면 자동 실행된다.\n", 310 | "```\n", 311 | "export WORKON_HOME='가상환경이 위치할 폴더'\n", 312 | "export VIRTUALENVWRAPPER_PYTHON='파이썬 경로'\n", 313 | "source /usr/local/bin/virtualenvwrapper.sh\n", 314 | "```" 315 | ] 316 | }, 317 | { 318 | "cell_type": "markdown", 319 | "metadata": { 320 | "slideshow": { 321 | "slide_type": "subslide" 322 | } 323 | }, 324 | "source": [ 325 | "##### 가상환경 만들기\n", 326 | "\n", 327 | "```\n", 328 | "> mkvirtualenv 가상환경이름\n", 329 | "```\n", 330 | "\n", 331 | "##### 가상환경 진입/변경\n", 332 | "\n", 333 | "```\n", 334 | "> workon 가상환경이름\n", 335 | "```\n", 336 | "\n", 337 | "##### 가상환경 나오기\n", 338 | "\n", 339 | "```\n", 340 | "> deactivate\n", 341 | "```\n", 342 | "\n", 343 | "##### postmkvirtualenv \n", 344 | "\n", 345 | "- 가상환경 생성 후 실행할 공통 명령\n", 346 | "\n", 347 | "```\n", 348 | "> echo 'pip install sphinx' >> $WORKON_HOME/postmkvirtualenv\n", 349 | "```" 350 | ] 351 | } 352 | ], 353 | "metadata": { 354 | "kernelspec": { 355 | "display_name": "Python 3", 356 | "language": "python", 357 | "name": "python3" 358 | }, 359 | "language_info": { 360 | "codemirror_mode": { 361 | "name": "ipython", 362 | "version": 3 363 | }, 364 | "file_extension": ".py", 365 | "mimetype": "text/x-python", 366 | "name": "python", 367 | "nbconvert_exporter": "python", 368 | "pygments_lexer": "ipython3", 369 | "version": "3.6.7" 370 | }, 371 | "varInspector": { 372 | "cols": { 373 | "lenName": 16, 374 | "lenType": 16, 375 | "lenVar": "50" 376 | }, 377 | "kernels_config": { 378 | "python": { 379 | "delete_cmd_postfix": "", 380 | "delete_cmd_prefix": "del ", 381 | "library": "var_list.py", 382 | "varRefreshCmd": "print(var_dic_list())" 383 | }, 384 | "r": { 385 | "delete_cmd_postfix": ") ", 386 | "delete_cmd_prefix": "rm(", 387 | "library": "var_list.r", 388 | "varRefreshCmd": "cat(var_dic_list()) " 389 | } 390 | }, 391 | "types_to_exclude": [ 392 | "module", 393 | "function", 394 | "builtin_function_or_method", 395 | "instance", 396 | "_Feature" 397 | ], 398 | "window_display": false 399 | } 400 | }, 401 | "nbformat": 4, 402 | "nbformat_minor": 2 403 | } 404 | -------------------------------------------------------------------------------- /day4/auxiliary_module.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | # create logger 4 | module_logger = logging.getLogger('spam_application.auxiliary') 5 | 6 | class Auxiliary: 7 | def __init__(self): 8 | self.logger = logging.getLogger('spam_application.auxiliary.Auxiliary') 9 | self.logger.info('creating an instance of Auxiliary') 10 | 11 | def do_something(self): 12 | self.logger.info('doing something') 13 | a = 1 + 1 14 | self.logger.info('done doing something') 15 | 16 | def some_function(): 17 | module_logger.info('received a call to "some_function"') -------------------------------------------------------------------------------- /day4/employeelogger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | # create logger 4 | logger = logging.getLogger(__name__) 5 | logger.setLevel(logging.INFO) 6 | 7 | # create formatter 8 | formatter = logging.Formatter('%(levelname)s:%(name)s:%(message)s') 9 | 10 | # create filehandler 11 | file_handler = logging.FileHandler('employee.log') 12 | file_handler.setFormatter(formatter) 13 | 14 | # add file_handler to logger 15 | logger.addHandler(file_handler) 16 | 17 | 18 | class Employee: 19 | """A sample Employee class""" 20 | 21 | def __init__(self, first, last): 22 | self.first = first 23 | self.last = last 24 | 25 | logger.info('Created Employee: {} - {}'.format(self.fullname, self.email)) 26 | 27 | @property 28 | def email(self): 29 | return '{}.{}@email.com'.format(self.first, self.last) 30 | 31 | @property 32 | def fullname(self): 33 | return '{} {}'.format(self.first, self.last) 34 | 35 | 36 | emp_1 = Employee('John', 'Smith') 37 | emp_2 = Employee('Corey', 'Schafer') 38 | emp_3 = Employee('Jane', 'Doe') -------------------------------------------------------------------------------- /day4/garbage collection.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 가비지 컬렉션\n", 8 | "\n", 9 | "참고자료:\n", 10 | "- https://winterj.me/python-gc/\n", 11 | "- https://rushter.com/blog/python-garbage-collector/\n", 12 | "- https://pymotw.com/3/gc/" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "## CPython의 GC 구성\n", 20 | "\n", 21 | "- reference counting + cyclic(generational) garbage collector\n", 22 | "- reference counting: 해당 객체의 참조 횟수 (0이 되면 메모리에서 할당 해제)\n", 23 | " - sys.getrefcount(*arg)\n", 24 | "- cyclic garbage: 참조 횟수가 0을 도달할 수 없는 경우" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 1, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import gc, sys, ctypes" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "### Reference Counting" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 2, 46 | "metadata": {}, 47 | "outputs": [ 48 | { 49 | "name": "stdout", 50 | "output_type": "stream", 51 | "text": [ 52 | "2\n" 53 | ] 54 | } 55 | ], 56 | "source": [ 57 | "foo = []\n", 58 | "print(sys.getrefcount(foo)) # 2회: foo 변수, getrefcount() 인자" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 3, 64 | "metadata": {}, 65 | "outputs": [ 66 | { 67 | "name": "stdout", 68 | "output_type": "stream", 69 | "text": [ 70 | "4\n" 71 | ] 72 | } 73 | ], 74 | "source": [ 75 | "def bar(a):\n", 76 | " print(sys.getrefcount(a))\n", 77 | "\n", 78 | "bar(foo) # 4회: foo 변수, getrefcount, 함수 인자, 함수 호출 스택" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "객체|값|\n", 86 | "---|---\n", 87 | "bar|\n", 88 | "getrefcount|\n", 89 | "a|foo\n", 90 | "\n", 91 | "객체|\\*args|\n", 92 | "---|---\n", 93 | "bar|foo\n", 94 | "\n", 95 | "객체|\\*args|\n", 96 | "---|---\n", 97 | "getrefcount|foo" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 4, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "name": "stdout", 107 | "output_type": "stream", 108 | "text": [ 109 | "2\n" 110 | ] 111 | } 112 | ], 113 | "source": [ 114 | "print(sys.getrefcount(foo)) # 2회. 함수 scope를 벗어났기 때문에 함수 관련 인자 X" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "### Cyclic Reference" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 5, 127 | "metadata": {}, 128 | "outputs": [ 129 | { 130 | "name": "stdout", 131 | "output_type": "stream", 132 | "text": [ 133 | "2\n", 134 | "3\n" 135 | ] 136 | } 137 | ], 138 | "source": [ 139 | "l = []\n", 140 | "print(sys.getrefcount(l)) # 2회: 변수 정의, print()\n", 141 | "\n", 142 | "l.append(l)\n", 143 | "print(sys.getrefcount(l)) # 변수 호출, append의 값, print()\n", 144 | "\n", 145 | "del l" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 6, 151 | "metadata": {}, 152 | "outputs": [ 153 | { 154 | "name": "stdout", 155 | "output_type": "stream", 156 | "text": [ 157 | "인스턴스 생성 직후, a = 2 and b = 2\n", 158 | "순환 참조, a = 3 and b = 3\n", 159 | "a 삭제 후, b = 3\n", 160 | "b는 여전히 a.x 를 참조: [{'x': <__main__.Foo object at 0x00000203B0C0C2B0>}, ]\n" 161 | ] 162 | } 163 | ], 164 | "source": [ 165 | "class Foo:\n", 166 | " def __init__(self):\n", 167 | " self.x = 0\n", 168 | "\n", 169 | "a = Foo()\n", 170 | "b = Foo()\n", 171 | "print('인스턴스 생성 직후, a = %d and b = %d' % (sys.getrefcount(a), sys.getrefcount(b)))\n", 172 | "\n", 173 | "a.x = b\n", 174 | "b.x = a\n", 175 | "print('순환 참조, a = %d and b = %d' % (sys.getrefcount(a), sys.getrefcount(b)))\n", 176 | "\n", 177 | "del a\n", 178 | "print('a 삭제 후, b = %d' % sys.getrefcount(b)) # a의 경우 1\n", 179 | "print('b는 여전히 a.x 를 참조: %s' % gc.get_referents(b))\n", 180 | "\n", 181 | "del b" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 7, 187 | "metadata": {}, 188 | "outputs": [ 189 | { 190 | "name": "stdout", 191 | "output_type": "stream", 192 | "text": [ 193 | "0\n", 194 | "0\n" 195 | ] 196 | } 197 | ], 198 | "source": [ 199 | "# 주소 탐색을 위해 ctypes 모듈 사용\n", 200 | "class PyObject(ctypes.Structure):\n", 201 | " _fields_ = [(\"refcnt\", ctypes.c_long)]\n", 202 | "\n", 203 | "gc.disable() # Disable generational gc\n", 204 | "\n", 205 | "lst1 = []\n", 206 | "lst1.append(lst1)\n", 207 | "\n", 208 | "# lst의 주소 저장\n", 209 | "lst1_address = id(lst1)\n", 210 | "\n", 211 | "# lst 해제\n", 212 | "del lst1\n", 213 | "\n", 214 | "object_1 = {}\n", 215 | "object_2 = {}\n", 216 | "object_1['obj2'] = object_2\n", 217 | "object_2['obj1'] = object_1\n", 218 | "\n", 219 | "obj_address = id(object_1)\n", 220 | "\n", 221 | "# 참조 해제\n", 222 | "del object_1, object_2\n", 223 | "\n", 224 | "gc.collect()\n", 225 | "\n", 226 | "# reference count. 메모리에 잔류하는 것을 확인\n", 227 | "print(PyObject.from_address(obj_address).refcnt)\n", 228 | "print(PyObject.from_address(lst1_address).refcnt)" 229 | ] 230 | }, 231 | { 232 | "cell_type": "markdown", 233 | "metadata": {}, 234 | "source": [ 235 | "### 파이썬 GC 모듈\n", 236 | "- Reference Counting 모듈을 보완\n", 237 | " - 자동 GC를 해제하려면 gc.set_threshold(0) > gc.disable()\n", 238 | " - Third-party에서 enable()하는 경우 종종 발생\n", 239 | " - 코드 내 순환 참조 유무에 대해 체크 필수\n", 240 | " - 굳이 disable()할 이유가 없다\n", 241 | "- 내부적으로 generation 및 threshold로 GC 주기 및 객체를 관리\n", 242 | " - 0세대: young (관리가 더 자주 일어남)\n", 243 | " - 각 객체는 한 세대에만 속함\n", 244 | " - 각 세대별 관리 주기는 gc.get_threshold() 함수를 통해 확인 가능\n", 245 | " - 0 -> 2세대 순\n", 246 | " - \\# allocation - \\# deallocation >= threshold\\[i] -> GC\n", 247 | " - \\# allocation - \\# deallocation >= threshold\\[i] * threshold\\[i+1] -> 차세대 GC\n", 248 | " - 예) 0세대는 700번마다, 1세대는 7천번 이후, 2세대는 7만번 이후\n", 249 | "- 각 세대별 할당 횟수 확인 후 위 기준 초과 시 gc.collect(generations=2) 수행\n", 250 | " - 2 -> 0세대 순\n", 251 | " - reference count가 0이 될 수 없는 객체 탐색\n", 252 | " - O: 상위 세대로 통합 / X: 메모리에서 해제" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": 8, 258 | "metadata": {}, 259 | "outputs": [ 260 | { 261 | "data": { 262 | "text/plain": [ 263 | "(700, 10, 10)" 264 | ] 265 | }, 266 | "execution_count": 8, 267 | "metadata": {}, 268 | "output_type": "execute_result" 269 | } 270 | ], 271 | "source": [ 272 | "gc.get_threshold()" 273 | ] 274 | }, 275 | { 276 | "cell_type": "markdown", 277 | "metadata": {}, 278 | "source": [ 279 | "### 순환 참조 탐지\n", 280 | "- 순환 참조는 Container 객체(tuple, list 등)에 의해서만 발생\n", 281 | "\n", 282 | "#### 방법\n", 283 | "1. 모든 컨테이너 객체 추적 (double-linked list로 관리)\n", 284 | "2. 해당 객체의 gc_refs 필드를 레퍼런스 카운트와 동일하게 설정\n", 285 | "3. 각 객체에서 참조하는 다른 컨테이너 객체를 찾아 해당 컨테이너의 gc_refs를 감소\n", 286 | " - gc_refs=0: 해당 객체들은 컨테이너 집합 내부에서 자기들끼리 참조\n", 287 | "5. gc_refs=0인 객체를 unreachable로 마킹 후 메모리에서 해제\n", 288 | "\n", 289 | "#### 알고리즘에 대한 상세 내용은 아래 링크 확인\n", 290 | " - https://github.com/python/cpython/blob/7d6ddb96b34b94c1cbdf95baa94492c48426404e/Modules/gcmodule.c#L902 (파이썬 GC모듈의 C코드)\n", 291 | " - http://arctrix.com/nas/python/gc/ (finalizer에 대한 이슈는 3.4에서 해결)\n", 292 | " - https://winterj.me/python-gc/#2-가비지-컬렉션의-작동-방식\n", 293 | " - 기반 언어에 따른 차이 有" 294 | ] 295 | }, 296 | { 297 | "cell_type": "code", 298 | "execution_count": 9, 299 | "metadata": {}, 300 | "outputs": [ 301 | { 302 | "name": "stdout", 303 | "output_type": "stream", 304 | "text": [ 305 | "(498, 0, 0)\n", 306 | "[[...]] True\n", 307 | "# in GC: 1\n" 308 | ] 309 | } 310 | ], 311 | "source": [ 312 | "gc.set_debug(gc.DEBUG_SAVEALL)\n", 313 | "\n", 314 | "print(gc.get_count())\n", 315 | "\n", 316 | "lst2 = []\n", 317 | "lst2.append(lst2)\n", 318 | "lst2_address = id(lst2)\n", 319 | "\n", 320 | "del lst2\n", 321 | "\n", 322 | "collected = gc.collect()\n", 323 | "\n", 324 | "for item in gc.garbage:\n", 325 | " print(item, lst2_address == id(item))\n", 326 | "\n", 327 | "print('# in GC: %d' % collected)" 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": null, 333 | "metadata": {}, 334 | "outputs": [], 335 | "source": [] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": null, 340 | "metadata": {}, 341 | "outputs": [], 342 | "source": [] 343 | } 344 | ], 345 | "metadata": { 346 | "kernelspec": { 347 | "display_name": "Python 3", 348 | "language": "python", 349 | "name": "python3" 350 | }, 351 | "language_info": { 352 | "codemirror_mode": { 353 | "name": "ipython", 354 | "version": 3 355 | }, 356 | "file_extension": ".py", 357 | "mimetype": "text/x-python", 358 | "name": "python", 359 | "nbconvert_exporter": "python", 360 | "pygments_lexer": "ipython3", 361 | "version": "3.6.8" 362 | } 363 | }, 364 | "nbformat": 4, 365 | "nbformat_minor": 2 366 | } 367 | -------------------------------------------------------------------------------- /day4/mylib.py: -------------------------------------------------------------------------------- 1 | # mylib.py 2 | import logging 3 | 4 | def do_something(): 5 | logging.info('Doing something') -------------------------------------------------------------------------------- /day4/profiler_test1.py: -------------------------------------------------------------------------------- 1 | def insertion_sort(data): 2 | result = [] 3 | for value in data: 4 | insert_value(result, value) 5 | return result 6 | 7 | # 삽입 정렬의 핵심메커니즘은 각 데이터의 삽입 지점을 찾는 함수 8 | # 아래는 극히 비효율적인 insert_value 함수로 입력 배열을 순차적으로 스캔 9 | 10 | def insert_value(array, value): 11 | for i, existing in enumerate(array): 12 | if existing > value: 13 | array.insert(i, value) 14 | return 15 | array.append(value) 16 | 17 | # insertion_sort와 insert_value를 프로파일하려고 난수로 구성된 데이터 집합을 생성하고, 프로파일러에 넘길 test 함수를 정의 18 | 19 | from random import randint 20 | 21 | max_size = 10 ** 4 22 | data = [randint(0, max_size) for _ in range(max_size)] 23 | test = lambda: insertion_sort(data) -------------------------------------------------------------------------------- /day4/profiler_test2.py: -------------------------------------------------------------------------------- 1 | @profile 2 | def do_stuff(numbers): 3 | print(numbers) 4 | 5 | numbers = 2 6 | do_stuff(numbers) 7 | -------------------------------------------------------------------------------- /day5/map_reduce_filter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Day 5. 데이터뽀개기 중급 파이썬 스터디 발표자료\n", 8 | "\n", 9 | "### Reference\n", 10 | "\n", 11 | "- 아래 글들을 참고해서 작성했습니다. 감사합니다!\n", 12 | "- [lambda operator와 map, reduce, filter](https://jupiny.com/2016/09/22/lambda-operator-map-reduce-filter/)\n", 13 | "- [함수형 프로그래밍과 filter map reduce에 대해서](https://jiwoochoi.tistory.com/60)\n", 14 | "\n", 15 | "### 5-3. Map, Reduce, Filter\n", 16 | "\n", 17 | "- 프로그래밍에서 함수적 접근을 쉽게 해주는 세가지 함수 (Higher Order Functions, 일종의 제너레이터로 Lazy evalution 영역)\n", 18 | "\n", 19 | "- lambda의 구조를 살펴보면, lambda [입력값] : [반환값]으로 되어 있음, Map, Reduce, Filter는 lambda랑 관련성이 높음\n", 20 | "\n", 21 | "> Note: If map & filter do not appear beautiful to you then you can read about list/dict/tuple comprehensions.\n", 22 | "\n", 23 | "\n", 24 | "\n", 25 | "\n", 26 | "\n", 27 | "\n", 28 | "\n", 29 | "\n", 30 | "- filter, map, reduce를 응용하게되면, 다음과 같은 이점을 가질 수 있습니다.\n", 31 | " - 의미가 잘 나타나는 코드를 갖출 수 있습니다! ex) filter => 필터한다!\n", 32 | " - 이터레이션을 위해 for loop을 돌릴필요가 없음\n", 33 | " - 코드 라인수가 짧아짐\n", 34 | "\n", 35 | "\n", 36 | "\n", 37 | "### 5-3-1. map([함수], [배열])\n", 38 | "\n", 39 | "- map 함수는 배열에서 원소를 하나씩 꺼내어 함수를 적용시킨 결과를 다시 상위 iterator에 담아 반환함\n", 40 | "- 함수가 한줄로 표현될 만큼 구성이 단순한 경우 lambda는 유용하고 map과 같이 사용할 수 있음\n", 41 | "- iterator는 next() 함수를 갖는 파이썬 객체로 꼭 메모리에 올릴 데이터만 올려서 메모리를 효율적으로 이용할 수 있는 파이썬의 대표적인 객체\n", 42 | "- 상위의 객체(추상적인 레벨)인 iterator로 return 하는 이유는 리스트가 아닌 다른 자료구조로 변환시킬 수도 있게 하는 것 (ex, set 자료구조)" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 2, 48 | "metadata": { 49 | "collapsed": false 50 | }, 51 | "outputs": [ 52 | { 53 | "data": { 54 | "text/plain": [ 55 | "[1, 4, 9]" 56 | ] 57 | }, 58 | "execution_count": 2, 59 | "metadata": {}, 60 | "output_type": "execute_result" 61 | } 62 | ], 63 | "source": [ 64 | "def square(x): \n", 65 | " return x**2\n", 66 | "\n", 67 | "list(map(square,[1, 2, 3]))" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 3, 73 | "metadata": { 74 | "collapsed": false 75 | }, 76 | "outputs": [ 77 | { 78 | "data": { 79 | "text/plain": [ 80 | "[1, 4, 9]" 81 | ] 82 | }, 83 | "execution_count": 3, 84 | "metadata": {}, 85 | "output_type": "execute_result" 86 | } 87 | ], 88 | "source": [ 89 | "list(map(lambda x: x**2, [1, 2, 3]))" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 16, 95 | "metadata": { 96 | "collapsed": false 97 | }, 98 | "outputs": [], 99 | "source": [ 100 | "map_it = map(lambda x: x**2, [1, 2, 3])" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 17, 106 | "metadata": { 107 | "collapsed": false 108 | }, 109 | "outputs": [ 110 | { 111 | "data": { 112 | "text/plain": [ 113 | "1" 114 | ] 115 | }, 116 | "execution_count": 17, 117 | "metadata": {}, 118 | "output_type": "execute_result" 119 | } 120 | ], 121 | "source": [ 122 | "next(map_it)" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 18, 128 | "metadata": { 129 | "collapsed": false 130 | }, 131 | "outputs": [ 132 | { 133 | "data": { 134 | "text/plain": [ 135 | "4" 136 | ] 137 | }, 138 | "execution_count": 18, 139 | "metadata": {}, 140 | "output_type": "execute_result" 141 | } 142 | ], 143 | "source": [ 144 | "next(map_it)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 19, 150 | "metadata": { 151 | "collapsed": false 152 | }, 153 | "outputs": [ 154 | { 155 | "data": { 156 | "text/plain": [ 157 | "9" 158 | ] 159 | }, 160 | "execution_count": 19, 161 | "metadata": {}, 162 | "output_type": "execute_result" 163 | } 164 | ], 165 | "source": [ 166 | "next(map_it)" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": 21, 172 | "metadata": { 173 | "collapsed": false 174 | }, 175 | "outputs": [ 176 | { 177 | "data": { 178 | "text/plain": [ 179 | "{1, 4, 9}" 180 | ] 181 | }, 182 | "execution_count": 21, 183 | "metadata": {}, 184 | "output_type": "execute_result" 185 | } 186 | ], 187 | "source": [ 188 | "set(map(lambda x: x**2, [1, 2, 3]))" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 23, 194 | "metadata": { 195 | "collapsed": false 196 | }, 197 | "outputs": [ 198 | { 199 | "data": { 200 | "text/plain": [ 201 | "(1, 4, 9)" 202 | ] 203 | }, 204 | "execution_count": 23, 205 | "metadata": {}, 206 | "output_type": "execute_result" 207 | } 208 | ], 209 | "source": [ 210 | "tuple(map(lambda x: x**2, [1, 2, 3]))" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 24, 216 | "metadata": { 217 | "collapsed": false 218 | }, 219 | "outputs": [ 220 | { 221 | "name": "stdout", 222 | "output_type": "stream", 223 | "text": [ 224 | "[0, 0]\n", 225 | "[1, 2]\n", 226 | "[4, 4]\n", 227 | "[9, 6]\n", 228 | "[16, 8]\n" 229 | ] 230 | } 231 | ], 232 | "source": [ 233 | "def multiply(x):\n", 234 | " return (x*x)\n", 235 | "\n", 236 | "def add(x):\n", 237 | " return (x+x)\n", 238 | "\n", 239 | "funcs = [multiply, add]\n", 240 | "\n", 241 | "for i in range(5):\n", 242 | " value = list(map(lambda x: x(i), funcs))\n", 243 | " print(value)" 244 | ] 245 | }, 246 | { 247 | "cell_type": "markdown", 248 | "metadata": {}, 249 | "source": [ 250 | "### 5-3-2. Reduce( [함수], [배열], [초기값])\n", 251 | "\n", 252 | "- Reduce는 배열에서 두 원소의 함수 출력값이 뒤에 나오는 원소와 함께 또다시 함수의 argument로 들어가며 과정이 순차적으로 반복되는 방식\n", 253 | "- 함수는 두 개의 parameter를 받는 함수, 초기값은 생략될수 있음 \n", 254 | "- 초기값이 있으면 초기값과 배열의 첫 원소가 맨 처음 함수로 전달되고. 초기값이 없다면 배열의 첫 번째와 두 번째 원소가 맨 처음 함수로 전달된다. " 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "execution_count": 4, 260 | "metadata": { 261 | "collapsed": false 262 | }, 263 | "outputs": [ 264 | { 265 | "name": "stdout", 266 | "output_type": "stream", 267 | "text": [ 268 | "(10, 20)\n", 269 | "(30, 30)\n", 270 | "(60, 40)\n", 271 | "(100, 50)\n" 272 | ] 273 | }, 274 | { 275 | "data": { 276 | "text/plain": [ 277 | "150" 278 | ] 279 | }, 280 | "execution_count": 4, 281 | "metadata": {}, 282 | "output_type": "execute_result" 283 | } 284 | ], 285 | "source": [ 286 | "import functools \n", 287 | "\n", 288 | "def sum(x,y): \n", 289 | " print((x,y))\n", 290 | " return x + y\n", 291 | "\n", 292 | "functools.reduce(sum, [10, 20, 30, 40, 50]) # 150 " 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": 5, 298 | "metadata": { 299 | "collapsed": false 300 | }, 301 | "outputs": [ 302 | { 303 | "data": { 304 | "text/plain": [ 305 | "150" 306 | ] 307 | }, 308 | "execution_count": 5, 309 | "metadata": {}, 310 | "output_type": "execute_result" 311 | } 312 | ], 313 | "source": [ 314 | "functools.reduce(lambda x,y: x+y, [10, 20, 30, 40, 50]) " 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": 6, 320 | "metadata": { 321 | "collapsed": false 322 | }, 323 | "outputs": [ 324 | { 325 | "data": { 326 | "text/plain": [ 327 | "9" 328 | ] 329 | }, 330 | "execution_count": 6, 331 | "metadata": {}, 332 | "output_type": "execute_result" 333 | } 334 | ], 335 | "source": [ 336 | "functools.reduce(lambda x,y: x if x>y else y, [1, 9, 3, 5, 6, 4]) " 337 | ] 338 | }, 339 | { 340 | "cell_type": "markdown", 341 | "metadata": {}, 342 | "source": [ 343 | "### 5-3-3. filter ( [함수], [배열])\n", 344 | "\n", 345 | "- filter는 배열에 있는 각각의 원소들을 함수에 parameter로 넘겨주어 함수의 출력값이 True인 경우에만 그 원소를 새로운 배열에 담아 반환한다." 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": 10, 351 | "metadata": { 352 | "collapsed": false 353 | }, 354 | "outputs": [ 355 | { 356 | "data": { 357 | "text/plain": [ 358 | "[4, 5]" 359 | ] 360 | }, 361 | "execution_count": 10, 362 | "metadata": {}, 363 | "output_type": "execute_result" 364 | } 365 | ], 366 | "source": [ 367 | "list(filter(lambda x: x>3, [1, 2, 3, 4, 5])) # [4, 5] " 368 | ] 369 | }, 370 | { 371 | "cell_type": "code", 372 | "execution_count": 11, 373 | "metadata": { 374 | "collapsed": false 375 | }, 376 | "outputs": [ 377 | { 378 | "data": { 379 | "text/plain": [ 380 | "[1, 4, 16, 25]" 381 | ] 382 | }, 383 | "execution_count": 11, 384 | "metadata": {}, 385 | "output_type": "execute_result" 386 | } 387 | ], 388 | "source": [ 389 | "#map, filter 사용 \n", 390 | "complicated_list = [1, 2, \"jupiny\", {}, [], 4, 5]\n", 391 | "\n", 392 | "list(map(lambda x: x**2, list(filter(lambda x: isinstance(x,int),complicated_list)))) # [1, 4, 16, 25] " 393 | ] 394 | }, 395 | { 396 | "cell_type": "markdown", 397 | "metadata": {}, 398 | "source": [ 399 | "### 1-100의 합을 구하라" 400 | ] 401 | }, 402 | { 403 | "cell_type": "code", 404 | "execution_count": 25, 405 | "metadata": { 406 | "collapsed": false 407 | }, 408 | "outputs": [ 409 | { 410 | "name": "stdout", 411 | "output_type": "stream", 412 | "text": [ 413 | "5050\n" 414 | ] 415 | } 416 | ], 417 | "source": [ 418 | "# C 언어 스타일의 해법\n", 419 | "sum_value = 0\n", 420 | "for i in range(1, 101) :\n", 421 | " sum_value += i \n", 422 | "print(sum_value)\n" 423 | ] 424 | }, 425 | { 426 | "cell_type": "code", 427 | "execution_count": 28, 428 | "metadata": { 429 | "collapsed": false 430 | }, 431 | "outputs": [ 432 | { 433 | "name": "stdout", 434 | "output_type": "stream", 435 | "text": [ 436 | "5050\n" 437 | ] 438 | } 439 | ], 440 | "source": [ 441 | "# python 스러운 해법\n", 442 | "sum_value = functools.reduce((lambda x,y : x+y), [x for x in range(1,101)])\n", 443 | "print(sum_value)" 444 | ] 445 | }, 446 | { 447 | "cell_type": "code", 448 | "execution_count": 31, 449 | "metadata": { 450 | "collapsed": false 451 | }, 452 | "outputs": [ 453 | { 454 | "name": "stdout", 455 | "output_type": "stream", 456 | "text": [ 457 | "5050\n" 458 | ] 459 | } 460 | ], 461 | "source": [ 462 | "# 하지만 Data scientist가 가장 먼저 생각해는 해법 \n", 463 | "import numpy as np\n", 464 | "print(np.sum([x for x in range(1,101)]))" 465 | ] 466 | }, 467 | { 468 | "cell_type": "markdown", 469 | "metadata": {}, 470 | "source": [ 471 | "### (옵션) MapReduce\n", 472 | "\n", 473 | "![](https://www.edureka.co/blog/wp-content/uploads/2016/11/MapReduce-Way-MapReduce-Tutorial-Edureka.png)\n", 474 | "\n", 475 | "- 하둡 맵리듀스 (Hadoop MapReduce): 분산 파일 시스템에 저장된 대용량 데이터의 병렬 처리를 위한 소프트웨어 프레임워크\n", 476 | "- 하둡 맵리듀스는 HDFS 상에서 동작하는 데이터 분석 프레임워크이다. 맵리듀스는 일반 프로그래밍 방법과는 다른 데이터 중심 프로그래밍 모형을 제공\n", 477 | "- 함수의 입력과 출력이 모두 키 (key)와 값 (value)의 쌍으로 구성되어 있다. 각 함수는 <키, 값> 쌍의 집합을 또다른 <키, 값> 쌍의 집합으로 변환한다. 맵 함수는 HDFS에서 불러온 데이터를 가공하여 새로운 <키, 값> 집합을 출력한다. 맵리듀스 시스템에서는 같은 키를 갖는 값들을 묶어 <키, (값1, 값2,· · ·)> 식의 새로운 <키, 값> 쌍의 집합을 만든다. 리듀스 함수는 여기에 집계 연산을 수행하여 또다른 <키, 값> 쌍의 집합을 생성하고 이를 HDFS에 저장한다." 478 | ] 479 | } 480 | ], 481 | "metadata": { 482 | "kernelspec": { 483 | "display_name": "Python 3", 484 | "language": "python", 485 | "name": "python3" 486 | }, 487 | "language_info": { 488 | "codemirror_mode": { 489 | "name": "ipython", 490 | "version": 3 491 | }, 492 | "file_extension": ".py", 493 | "mimetype": "text/x-python", 494 | "name": "python", 495 | "nbconvert_exporter": "python", 496 | "pygments_lexer": "ipython3", 497 | "version": "3.5.1rc1" 498 | } 499 | }, 500 | "nbformat": 4, 501 | "nbformat_minor": 2 502 | } 503 | -------------------------------------------------------------------------------- /day5/multiprocessing.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | from threading import Thread 3 | import multiprocessing 4 | 5 | 6 | def singleCount(cnt, name): 7 | for i in range(1, 1000001): 8 | cnt += 1 9 | 10 | # single process start 11 | @profile 12 | def single_process(lists): 13 | cnt = 0 14 | for each in lists: 15 | singleCount(cnt, each) 16 | 17 | # multi process start 18 | @profile 19 | def multi_process(lists): 20 | cnt = 0 21 | pool = multiprocessing.Pool(processes=4) 22 | func = partial(singleCount, cnt) 23 | pool.map(func, lists) 24 | pool.close() 25 | pool.join() 26 | 27 | # multi threading start 28 | @profile 29 | def multi_thread(): 30 | cnt = 0 31 | th1 = Thread(target=singleCount, args=(cnt, "1")) 32 | th1.start() 33 | th1.join() 34 | th2 = Thread(target=singleCount, args=(cnt, "2")) 35 | th2.start() 36 | th2.join() 37 | th3 = Thread(target=singleCount, args=(cnt, "3")) 38 | th3.start() 39 | th3.join() 40 | th4 = Thread(target=singleCount, args=(cnt, "4")) 41 | th4.start() 42 | th4.join() 43 | 44 | lists = ['1', '2', '3', '4'] 45 | single_process(lists) 46 | multi_process(lists) 47 | multi_thread() 48 | -------------------------------------------------------------------------------- /day5/multiprocessing2.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | from threading import Thread 3 | import multiprocessing 4 | 5 | 6 | def singleCount(cnt, name): 7 | for i in range(1, 1000001): 8 | cnt += 1 9 | 10 | # single process start 11 | @profile 12 | def single_process(lists): 13 | cnt = 0 14 | for each in lists: 15 | singleCount(cnt, each) 16 | 17 | # multi process start 18 | @profile 19 | def multi_process(lists): 20 | cnt = 0 21 | pool = multiprocessing.Pool(processes=4) 22 | func = partial(singleCount, cnt) 23 | pool.map_async(func, lists) 24 | pool.close() 25 | pool.join() 26 | 27 | # multi threading start 28 | @profile 29 | def multi_thread(): 30 | cnt = 0 31 | th1 = Thread(target=singleCount, args=(cnt, "1")) 32 | th1.start() 33 | th1.join() 34 | th2 = Thread(target=singleCount, args=(cnt, "2")) 35 | th2.start() 36 | th2.join() 37 | th3 = Thread(target=singleCount, args=(cnt, "3")) 38 | th3.start() 39 | th3.join() 40 | th4 = Thread(target=singleCount, args=(cnt, "4")) 41 | th4.start() 42 | th4.join() 43 | 44 | lists = ['1', '2', '3', '4'] 45 | single_process(lists) 46 | multi_process(lists) 47 | multi_thread() 48 | -------------------------------------------------------------------------------- /day6/_hello_cpp.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaggleBreak/interpy-kr/6a5e045e2ee3d1a72ea78659c8cb51b5219a9904/day6/_hello_cpp.so -------------------------------------------------------------------------------- /day6/add.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int add_int(int, int); 4 | float add_float(float, float); 5 | 6 | int add_int(int num1, int num2){ 7 | return num1 + num2; 8 | } 9 | 10 | float add_float(float num1, float num2){ 11 | return num1 + num2; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /day6/function caching.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "slideshow": { 7 | "slide_type": "slide" 8 | } 9 | }, 10 | "source": [ 11 | "## Function Caching (Memoization)" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": { 17 | "slideshow": { 18 | "slide_type": "slide" 19 | } 20 | }, 21 | "source": [ 22 | "##### Fibonacci numbers" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 26, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "import time" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 56, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "@lru_cache(maxsize=128)\n", 41 | "def fib(n):\n", 42 | " print(n)\n", 43 | " if n < 2:\n", 44 | " return n\n", 45 | " return fib(n-1) + fib(n-2)" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 58, 51 | "metadata": { 52 | "scrolled": false 53 | }, 54 | "outputs": [ 55 | { 56 | "name": "stdout", 57 | "output_type": "stream", 58 | "text": [ 59 | "10\n", 60 | "9\n", 61 | "55\n", 62 | "소요시간: 0.0 초\n" 63 | ] 64 | } 65 | ], 66 | "source": [ 67 | "start = time.time()\n", 68 | "print(fib(35))\n", 69 | "print(\"소요시간: %s 초\" % str(round(time.time() - start, 2)))" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": { 75 | "slideshow": { 76 | "slide_type": "-" 77 | } 78 | }, 79 | "source": [ 80 | "##### 시간 및 계산 비용이 크다\n", 81 | "- 재귀호출을 2^n - 1번 한다.\n", 82 | "- 숫자가 커질수록 중복 계산횟수가 기하급수적으로 늘어난다." 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 29, 88 | "metadata": { 89 | "slideshow": { 90 | "slide_type": "-" 91 | } 92 | }, 93 | "outputs": [ 94 | { 95 | "data": { 96 | "text/plain": [ 97 | "68719476735" 98 | ] 99 | }, 100 | "execution_count": 29, 101 | "metadata": {}, 102 | "output_type": "execute_result" 103 | } 104 | ], 105 | "source": [ 106 | "# fib(36)\n", 107 | "\n", 108 | "(2 ** 36) - 1" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": { 114 | "slideshow": { 115 | "slide_type": "slide" 116 | } 117 | }, 118 | "source": [ 119 | "##### 재귀호출은 (2^n)-1 번 수행하지만, 실제 필요한 함수의 결과값은 n개 뿐이다.\n", 120 | "- 한 번 계산한 결과를 저장하고\n", 121 | "- 저장한 값을 꺼내 쓰는 방식으로 바꿔보자" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 30, 127 | "metadata": {}, 128 | "outputs": [], 129 | "source": [ 130 | "cache = {}\n", 131 | "\n", 132 | "def fib(n):\n", 133 | " if n in cache:\n", 134 | " return cache[n]\n", 135 | " \n", 136 | " if n < 2:\n", 137 | " return n\n", 138 | " \n", 139 | " cache[n] = fib(n-1) + fib(n-2)\n", 140 | " return cache[n]" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 31, 146 | "metadata": {}, 147 | "outputs": [ 148 | { 149 | "data": { 150 | "text/plain": [ 151 | "14930352" 152 | ] 153 | }, 154 | "execution_count": 31, 155 | "metadata": {}, 156 | "output_type": "execute_result" 157 | } 158 | ], 159 | "source": [ 160 | "fib(36)" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 32, 166 | "metadata": { 167 | "slideshow": { 168 | "slide_type": "slide" 169 | } 170 | }, 171 | "outputs": [ 172 | { 173 | "data": { 174 | "text/plain": [ 175 | "{2: 1,\n", 176 | " 3: 2,\n", 177 | " 4: 3,\n", 178 | " 5: 5,\n", 179 | " 6: 8,\n", 180 | " 7: 13,\n", 181 | " 8: 21,\n", 182 | " 9: 34,\n", 183 | " 10: 55,\n", 184 | " 11: 89,\n", 185 | " 12: 144,\n", 186 | " 13: 233,\n", 187 | " 14: 377,\n", 188 | " 15: 610,\n", 189 | " 16: 987,\n", 190 | " 17: 1597,\n", 191 | " 18: 2584,\n", 192 | " 19: 4181,\n", 193 | " 20: 6765,\n", 194 | " 21: 10946,\n", 195 | " 22: 17711,\n", 196 | " 23: 28657,\n", 197 | " 24: 46368,\n", 198 | " 25: 75025,\n", 199 | " 26: 121393,\n", 200 | " 27: 196418,\n", 201 | " 28: 317811,\n", 202 | " 29: 514229,\n", 203 | " 30: 832040,\n", 204 | " 31: 1346269,\n", 205 | " 32: 2178309,\n", 206 | " 33: 3524578,\n", 207 | " 34: 5702887,\n", 208 | " 35: 9227465,\n", 209 | " 36: 14930352}" 210 | ] 211 | }, 212 | "execution_count": 32, 213 | "metadata": {}, 214 | "output_type": "execute_result" 215 | } 216 | ], 217 | "source": [ 218 | "cache" 219 | ] 220 | }, 221 | { 222 | "cell_type": "markdown", 223 | "metadata": { 224 | "slideshow": { 225 | "slide_type": "slide" 226 | } 227 | }, 228 | "source": [ 229 | "##### Memoization\n", 230 | "- 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술." 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": { 236 | "slideshow": { 237 | "slide_type": "slide" 238 | } 239 | }, 240 | "source": [ 241 | "##### 좀 더 쉽게 쓸 수 있도록 데코레이터로 만들어보자" 242 | ] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": 33, 247 | "metadata": {}, 248 | "outputs": [], 249 | "source": [ 250 | "def memoize(f):\n", 251 | " cache = {}\n", 252 | " \n", 253 | " def wrapper(n):\n", 254 | " if n in cache:\n", 255 | " return cache[n]\n", 256 | " \n", 257 | " cache[n] = f(n)\n", 258 | " \n", 259 | " return cache[n]\n", 260 | " \n", 261 | " return wrapper" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 35, 267 | "metadata": {}, 268 | "outputs": [], 269 | "source": [ 270 | "@memoize\n", 271 | "def fib(n):\n", 272 | " if n < 2:\n", 273 | " return n\n", 274 | " return fib(n-1) + fib(n-2)" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 36, 280 | "metadata": {}, 281 | "outputs": [ 282 | { 283 | "data": { 284 | "text/plain": [ 285 | "9227465" 286 | ] 287 | }, 288 | "execution_count": 36, 289 | "metadata": {}, 290 | "output_type": "execute_result" 291 | } 292 | ], 293 | "source": [ 294 | "fib(35)" 295 | ] 296 | }, 297 | { 298 | "cell_type": "markdown", 299 | "metadata": {}, 300 | "source": [ 301 | "- 함수는 1개의 인자만 받는다(n)\n", 302 | "- 그 인자는 사전의 키가 될 수 있는 객체여야 한다" 303 | ] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "metadata": { 308 | "slideshow": { 309 | "slide_type": "slide" 310 | } 311 | }, 312 | "source": [ 313 | "##### 개선된 데코레이터" 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": 41, 319 | "metadata": {}, 320 | "outputs": [], 321 | "source": [ 322 | "def memoize(f):\n", 323 | " cache = {}\n", 324 | " \n", 325 | " def wrapper(*args, **kwargs):\n", 326 | " key = str(args) + str(kwargs)\n", 327 | " \n", 328 | " if key in cache:\n", 329 | " return cache[key]\n", 330 | " \n", 331 | " cache[key] = f(*args, **kwargs)\n", 332 | " print(cache)\n", 333 | " \n", 334 | " return cache[key]\n", 335 | " \n", 336 | " return wrapper" 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": 42, 342 | "metadata": {}, 343 | "outputs": [], 344 | "source": [ 345 | "@memoize\n", 346 | "def add(a, b):\n", 347 | " return a + b" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": 43, 353 | "metadata": {}, 354 | "outputs": [ 355 | { 356 | "name": "stdout", 357 | "output_type": "stream", 358 | "text": [ 359 | "{'(4, 5){}': 9}\n" 360 | ] 361 | }, 362 | { 363 | "data": { 364 | "text/plain": [ 365 | "9" 366 | ] 367 | }, 368 | "execution_count": 43, 369 | "metadata": {}, 370 | "output_type": "execute_result" 371 | } 372 | ], 373 | "source": [ 374 | "add(4, 5)" 375 | ] 376 | }, 377 | { 378 | "cell_type": "markdown", 379 | "metadata": { 380 | "slideshow": { 381 | "slide_type": "slide" 382 | } 383 | }, 384 | "source": [ 385 | "##### 파이썬 3.2+부터 lru_cache 데코레이터를 사용해서 쉽게 함수의 반환값들을 캐싱할 수 있다.\n", 386 | "- lru_cache 데코레이터는 주어진 함수를 더 빨리 작동하도록 해준다.\n", 387 | "- LRU(least recently used) 알고리즘으로 동작." 388 | ] 389 | }, 390 | { 391 | "cell_type": "code", 392 | "execution_count": 44, 393 | "metadata": {}, 394 | "outputs": [], 395 | "source": [ 396 | "from functools import lru_cache" 397 | ] 398 | }, 399 | { 400 | "cell_type": "code", 401 | "execution_count": 45, 402 | "metadata": {}, 403 | "outputs": [], 404 | "source": [ 405 | "@lru_cache(maxsize=128)\n", 406 | "def fib(n):\n", 407 | " if n < 2:\n", 408 | " return n\n", 409 | " return fib(n-1) + fib(n-2)" 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": 46, 415 | "metadata": {}, 416 | "outputs": [ 417 | { 418 | "data": { 419 | "text/plain": [ 420 | "9227465" 421 | ] 422 | }, 423 | "execution_count": 46, 424 | "metadata": {}, 425 | "output_type": "execute_result" 426 | } 427 | ], 428 | "source": [ 429 | "fib(35)" 430 | ] 431 | }, 432 | { 433 | "cell_type": "markdown", 434 | "metadata": { 435 | "slideshow": { 436 | "slide_type": "slide" 437 | } 438 | }, 439 | "source": [ 440 | "##### lru_cache를 이용하여 동일한 함수를 반복 수행하면 그냥 캐시를 읽는 것 밖에 안되므로 0에 가까워짐" 441 | ] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "execution_count": 49, 446 | "metadata": {}, 447 | "outputs": [ 448 | { 449 | "name": "stdout", 450 | "output_type": "stream", 451 | "text": [ 452 | "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125\n", 453 | "소요시간: 0.0064718723 초\n" 454 | ] 455 | } 456 | ], 457 | "source": [ 458 | "start = time.time()\n", 459 | "print(fib(500))\n", 460 | "print(\"소요시간: %s 초\" % str(round(time.time() - start, 10)))" 461 | ] 462 | }, 463 | { 464 | "cell_type": "code", 465 | "execution_count": 52, 466 | "metadata": {}, 467 | "outputs": [ 468 | { 469 | "name": "stdout", 470 | "output_type": "stream", 471 | "text": [ 472 | "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125\n", 473 | "소요시간: 0.0023369789 초\n" 474 | ] 475 | } 476 | ], 477 | "source": [ 478 | "start = time.time()\n", 479 | "print(fib(500))\n", 480 | "print(\"소요시간: %s 초\" % str(round(time.time() - start, 10)))" 481 | ] 482 | }, 483 | { 484 | "cell_type": "markdown", 485 | "metadata": { 486 | "slideshow": { 487 | "slide_type": "-" 488 | } 489 | }, 490 | "source": [ 491 | "##### 캐시 지우기" 492 | ] 493 | }, 494 | { 495 | "cell_type": "code", 496 | "execution_count": 51, 497 | "metadata": {}, 498 | "outputs": [], 499 | "source": [ 500 | "fib.cache_clear()" 501 | ] 502 | }, 503 | { 504 | "cell_type": "markdown", 505 | "metadata": { 506 | "slideshow": { 507 | "slide_type": "slide" 508 | } 509 | }, 510 | "source": [ 511 | "#### 주의사항\n", 512 | "- 캐시에 저장한 값을 다시 꺼내쓰는 일이 적다면, 성능향상보다 캐시를 유지하는 데 드는 비용이 더 클 수 있다.\n", 513 | "- float의 부동소수점이 가지는 오차때문에 memoization 적용으로 인한 유익이 없을 수도 있다." 514 | ] 515 | } 516 | ], 517 | "metadata": { 518 | "kernelspec": { 519 | "display_name": "Python 3", 520 | "language": "python", 521 | "name": "python3" 522 | }, 523 | "language_info": { 524 | "codemirror_mode": { 525 | "name": "ipython", 526 | "version": 3 527 | }, 528 | "file_extension": ".py", 529 | "mimetype": "text/x-python", 530 | "name": "python", 531 | "nbconvert_exporter": "python", 532 | "pygments_lexer": "ipython3", 533 | "version": "3.6.7" 534 | }, 535 | "varInspector": { 536 | "cols": { 537 | "lenName": 16, 538 | "lenType": 16, 539 | "lenVar": "50" 540 | }, 541 | "kernels_config": { 542 | "python": { 543 | "delete_cmd_postfix": "", 544 | "delete_cmd_prefix": "del ", 545 | "library": "var_list.py", 546 | "varRefreshCmd": "print(var_dic_list())" 547 | }, 548 | "r": { 549 | "delete_cmd_postfix": ") ", 550 | "delete_cmd_prefix": "rm(", 551 | "library": "var_list.r", 552 | "varRefreshCmd": "cat(var_dic_list()) " 553 | } 554 | }, 555 | "types_to_exclude": [ 556 | "module", 557 | "function", 558 | "builtin_function_or_method", 559 | "instance", 560 | "_Feature" 561 | ], 562 | "window_display": false 563 | } 564 | }, 565 | "nbformat": 4, 566 | "nbformat_minor": 2 567 | } 568 | -------------------------------------------------------------------------------- /day6/hello_cpp.cpp: -------------------------------------------------------------------------------- 1 | #include "hello_cpp.h" 2 | CHello::CHello() { 3 | } 4 | 5 | CHello::~CHello() { 6 | } 7 | 8 | void CHello::hello1(char *name) 9 | { 10 | cout << "Hello " << name << endl; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /day6/hello_cpp.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class CHello { 5 | public : 6 | CHello(); 7 | virtual ~CHello(); 8 | 9 | void hello1(char *name); 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /day6/hello_cpp.i: -------------------------------------------------------------------------------- 1 | %module hello_cpp 2 | %{ 3 | #include "hello_cpp.h" 4 | %} 5 | %include "hello_cpp.h" 6 | 7 | -------------------------------------------------------------------------------- /day6/hello_cpp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaggleBreak/interpy-kr/6a5e045e2ee3d1a72ea78659c8cb51b5219a9904/day6/hello_cpp.o -------------------------------------------------------------------------------- /day6/hello_cpp.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 3.0.8 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | 8 | 9 | 10 | 11 | from sys import version_info 12 | if version_info >= (2, 6, 0): 13 | def swig_import_helper(): 14 | from os.path import dirname 15 | import imp 16 | fp = None 17 | try: 18 | fp, pathname, description = imp.find_module('_hello_cpp', [dirname(__file__)]) 19 | except ImportError: 20 | import _hello_cpp 21 | return _hello_cpp 22 | if fp is not None: 23 | try: 24 | _mod = imp.load_module('_hello_cpp', fp, pathname, description) 25 | finally: 26 | fp.close() 27 | return _mod 28 | _hello_cpp = swig_import_helper() 29 | del swig_import_helper 30 | else: 31 | import _hello_cpp 32 | del version_info 33 | try: 34 | _swig_property = property 35 | except NameError: 36 | pass # Python < 2.2 doesn't have 'property'. 37 | 38 | 39 | def _swig_setattr_nondynamic(self, class_type, name, value, static=1): 40 | if (name == "thisown"): 41 | return self.this.own(value) 42 | if (name == "this"): 43 | if type(value).__name__ == 'SwigPyObject': 44 | self.__dict__[name] = value 45 | return 46 | method = class_type.__swig_setmethods__.get(name, None) 47 | if method: 48 | return method(self, value) 49 | if (not static): 50 | if _newclass: 51 | object.__setattr__(self, name, value) 52 | else: 53 | self.__dict__[name] = value 54 | else: 55 | raise AttributeError("You cannot add attributes to %s" % self) 56 | 57 | 58 | def _swig_setattr(self, class_type, name, value): 59 | return _swig_setattr_nondynamic(self, class_type, name, value, 0) 60 | 61 | 62 | def _swig_getattr_nondynamic(self, class_type, name, static=1): 63 | if (name == "thisown"): 64 | return self.this.own() 65 | method = class_type.__swig_getmethods__.get(name, None) 66 | if method: 67 | return method(self) 68 | if (not static): 69 | return object.__getattr__(self, name) 70 | else: 71 | raise AttributeError(name) 72 | 73 | def _swig_getattr(self, class_type, name): 74 | return _swig_getattr_nondynamic(self, class_type, name, 0) 75 | 76 | 77 | def _swig_repr(self): 78 | try: 79 | strthis = "proxy of " + self.this.__repr__() 80 | except Exception: 81 | strthis = "" 82 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 83 | 84 | try: 85 | _object = object 86 | _newclass = 1 87 | except AttributeError: 88 | class _object: 89 | pass 90 | _newclass = 0 91 | 92 | 93 | class CHello(_object): 94 | __swig_setmethods__ = {} 95 | __setattr__ = lambda self, name, value: _swig_setattr(self, CHello, name, value) 96 | __swig_getmethods__ = {} 97 | __getattr__ = lambda self, name: _swig_getattr(self, CHello, name) 98 | __repr__ = _swig_repr 99 | 100 | def __init__(self): 101 | this = _hello_cpp.new_CHello() 102 | try: 103 | self.this.append(this) 104 | except Exception: 105 | self.this = this 106 | __swig_destroy__ = _hello_cpp.delete_CHello 107 | __del__ = lambda self: None 108 | 109 | def hello1(self, name): 110 | return _hello_cpp.CHello_hello1(self, name) 111 | CHello_swigregister = _hello_cpp.CHello_swigregister 112 | CHello_swigregister(CHello) 113 | 114 | # This file is compatible with both classic and new-style classes. 115 | 116 | 117 | -------------------------------------------------------------------------------- /day6/hello_cpp_wrap.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaggleBreak/interpy-kr/6a5e045e2ee3d1a72ea78659c8cb51b5219a9904/day6/hello_cpp_wrap.o -------------------------------------------------------------------------------- /day6/img/Capture.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaggleBreak/interpy-kr/6a5e045e2ee3d1a72ea78659c8cb51b5219a9904/day6/img/Capture.PNG -------------------------------------------------------------------------------- /day7/CustomLogger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | class SingletonType(type): 4 | def __call__(cls, *args, **kwargs): 5 | try: 6 | return cls.__instance 7 | except AttributeError: 8 | cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs) 9 | return cls.__instance 10 | 11 | class CustomLogger(object): 12 | __metaclass__ = SingletonType 13 | _logger = None 14 | 15 | def __init__(self): 16 | self._logger = logging.getLogger("crumbs") 17 | self._logger.setLevel(logging.DEBUG) 18 | formatter = logging.Formatter('[%(levelname)s|%(filename)s:%(lineno)s] %(asctime)s > %(message)s') 19 | 20 | import datetime 21 | now = datetime.datetime.now() 22 | import time 23 | timestamp = time.mktime(now.timetuple()) 24 | 25 | dirname = './log' 26 | if not os.path.isdir(dirname): 27 | os.mkdir(dirname) 28 | fileHandler = logging.FileHandler(dirname + "/Aries_"+now.strftime("%Y-%m-%d %H:%M:%S")+".log") 29 | streamHandler = logging.StreamHandler() 30 | 31 | fileHandler.setFormatter(formatter) 32 | streamHandler.setFormatter(formatter) 33 | 34 | self._logger.addHandler(fileHandler) 35 | self._logger.addHandler(streamHandler) 36 | 37 | def get_logger(self): 38 | return self._logger 39 | 40 | -------------------------------------------------------------------------------- /day7/context_manager.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Day 7. 데이터뽀개기 중급 파이썬 스터디 발표자료\n", 8 | "\n", 9 | "### Reference\n", 10 | "\n", 11 | "- 아래 글들을 참고해서 작성했습니다. 감사합니다!\n", 12 | "- [24. Context manager](https://ddanggle.gitbooks.io/interpy-kr/content/ch24-context-manager.html)\n", 13 | "- [파이썬 context manager, with구문으로 안전한 리소스 관리를 하자.](https://velog.io/@sjquant/%ED%8C%8C%EC%9D%B4%EC%8D%AC-context-manager-with%EA%B5%AC%EB%AC%B8%EC%9C%BC%EB%A1%9C-%EC%95%88%EC%A0%84%ED%95%9C-%EB%A6%AC%EC%86%8C%EC%8A%A4-%EA%B4%80%EB%A6%AC%EB%A5%BC-%ED%95%98%EC%9E%90.)\n", 14 | "- [텐서플로우 문서 한글 번역본](https://tensorflowkorea.gitbooks.io/tensorflow-kr/content/g3doc/get_started/basic_usage.html)\n", 15 | "- [이펙티브 텐서플로 2.0](https://tensorflow.blog/2019/02/21/%EC%9D%B4%ED%8E%99%ED%8B%B0%EB%B8%8C-%ED%85%90%EC%84%9C%ED%94%8C%EB%A1%9C-2-0/)\n", 16 | "\n", 17 | "\n", 18 | "### 7-1. with\n", 19 | "\n", 20 | "- 컨텍스트 매니저는 원하는 타이밍에 정확하게 리소스를 할당하고 제공하는 역할. 가장 많이 사용되는 컨텍스트 매니저는 with 문입니다. \n", 21 | "\n", 22 | "- with 를 사용할 때 \n", 23 | "```\n", 24 | "with open('some_file', 'w') as opened_file:\n", 25 | " opened_file.write('Hola')\n", 26 | "```\n", 27 | "\n", 28 | "- 위 코드와 동일한 수행을 하는 코드\n", 29 | "```\n", 30 | "file = open('somefile', 'w')\n", 31 | "try:\n", 32 | " file.write('Hola')\n", 33 | "finally:\n", 34 | " file.close()\n", 35 | "```\n", 36 | "\n", 37 | "- 예시와 비교해보면 간단히 with을 사용함으로써 많은 표준 코드들을 삭제했음, with 문을 사용해서 가장 큰 장점은 감싸진 블록이 존재하든지 관심을 가지지 않아도 파일은 확실히 닫아진다는 것입니다.\n", 38 | "- 일반적으로 파일을 잠그거나 해제하거나, (이미 보여드렸듯) 열려있는 파일을 닫을 때 컨텍스트 매니저를 사용함" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "### 7-2. Class로 Context Manager 향상시키기\n", 46 | "\n", 47 | "- 최소한 컨텍스트 매니저는 `__enter__` 과 `__exit__` 메소드 (Magic Methods)를 가지고 있음\n", 48 | "- 파일을 여는 컨텍스트 매니저를 만들어보면서 기본에 대해서 살펴봅시다." 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 1, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "class File(object):\n", 58 | " def __init__(self, file_name, method):\n", 59 | " self.file_obj = open(file_name, method)\n", 60 | " def __enter__(self):\n", 61 | " return self.file_obj\n", 62 | " def __exit__(self, type, value, trace_back):\n", 63 | " self.file_obj.close()" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 8, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "with File('demo.txt', 'wb') as opened_file:\n", 73 | " opened_file.write(b'Hola!')" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "- `__exit__` 함수는 세 가지 전달 인자를 받습니다. 컨텍스트 매니저 class의 일부인 모든 `__exit__` 메소드에 필요함\n", 81 | " * 1) with문은 File(class)의 `__exit__` 메소드를 저장, \n", 82 | " * 2) File(class)의 `__enter__` 메소드를 호출\n", 83 | " * 3) `enter` 메소드는 파일을 열고 파일을 반환\n", 84 | " * 4) 열려진 파일 처리는 opened_file을 통과합니다.\n", 85 | " * 5) .write()를 사용해서 파일을 쓸 수 있습니다.\n", 86 | " * 6) with문은 저장된 `__exit__` 문을 호출\n", 87 | " * 7) `__exit__`문은 파일을 닫습니다." 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "### 7-3. handling exception\n", 95 | "\n", 96 | "- 아직까지 `__exit__` 메소드의 인자인 type, value, trace_back에 대해서는 아직 이야기를 나누지 않았음\n", 97 | "- 4번째에서 6번째 단계 사이에서 예외가 발생한다면, 파이썬은 예외에서의 type, value, trace_back을 `__exit__`메소드에 통과시킵니다. \n", 98 | "- `__exit__` 메소드에서는 다음에 어떤 단계들이 요구되는 지에 따라 파일을 닫을 수 있는 방법을 결정해야합니다. 이 경우에는 거기까지는 생각하지 않겠습니다.\n", 99 | "- 어떤 파일 객체에서 예외를 발생한다면 어떻게 될까요? 파일 객체가 지원되지 않는 메소드에 접근하려 한다고 생각해보겠습니다. 예를 들면," 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 9, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "ename": "AttributeError", 109 | "evalue": "'_io.BufferedWriter' object has no attribute 'undefined_function'", 110 | "output_type": "error", 111 | "traceback": [ 112 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 113 | "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", 114 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'demo.txt'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'wb'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mopened_file\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mopened_file\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mundefined_function\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mb'Hola!'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 115 | "\u001b[0;31mAttributeError\u001b[0m: '_io.BufferedWriter' object has no attribute 'undefined_function'" 116 | ] 117 | } 118 | ], 119 | "source": [ 120 | "with File('demo.txt', 'wb') as opened_file:\n", 121 | " opened_file.undefined_function(b'Hola!')" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "- with 문이 에러를 만나면, 어떤식으로 처리되는지 단계들을 살펴보기\n", 129 | "\n", 130 | " * 1) type, value, traceback의 에러가 `_exit`메소드를 통과합니다.\n", 131 | " * 2) `__exit__` 메소드가 예외를 처리하도록 합니다.\n", 132 | " * 3) `__exit__` 메소드가 True 를 반환한다면, 예외는 적절하게 된 것입니다.\n", 133 | " * 4) `__exit__` 메소드가 True가 아닌 다른 것을 반환하면, with문에서 예외가 발생합니다.\n", 134 | "\n", 135 | "- 위 경우에는 `__exit__` 메소드는 None(리턴 문이 어떤 것도 만나지 않는다면 None을 반환)을 반환합니다. 그래서, with문은 예외를 발생시킵니다." 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 11, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "class File(object):\n", 145 | " def __init__(self, file_name, method):\n", 146 | " self.file_obj = open(file_name, method)\n", 147 | " def __enter__(self):\n", 148 | " return self.file_obj\n", 149 | " def __exit__(self, type, value, trace_back):\n", 150 | " print(\"예외는 처리되어야 합니다\")\n", 151 | " self.file_obj.close()\n", 152 | " return True" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": 13, 158 | "metadata": {}, 159 | "outputs": [ 160 | { 161 | "name": "stdout", 162 | "output_type": "stream", 163 | "text": [ 164 | "예외는 처리되어야 합니다\n" 165 | ] 166 | } 167 | ], 168 | "source": [ 169 | "with File('demo.txt', 'wb') as opened_file:\n", 170 | " opened_file.undefined_function()" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "- `__exit__` 메소드가 True를 반환한다면, with문에서 에외는 발생하지 않을 것입니다." 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": {}, 183 | "source": [ 184 | "### 7-4. 제너레이터를 활용해서 컨텍스트 매니저 향상시키기\n", 185 | "\n", 186 | "- 데코레이터와 제너레이터를 활용해서 컨텍스트 매니저를 향상시킬 수도 있음 (파이썬은 contextlib 모듈) \n", 187 | "- class 대신에, 컨텍스트 매니저를 제너레이터 함수를 이용해서 향상시킬 수도 있습니다. 의미없는 예시를 보면서, 기본부터 확인 해보겠습니다." 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": 14, 193 | "metadata": {}, 194 | "outputs": [], 195 | "source": [ 196 | "from contextlib import contextmanager\n", 197 | "\n", 198 | "@contextmanager\n", 199 | "def open_file(name):\n", 200 | " f = open(name, 'wb')\n", 201 | " yield f\n", 202 | " f.close()" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "- 메소드는 제너레이터, yield, 데코레이터에 관한 지식들이 필요합니다.\n", 210 | "- 이 예시에서는 일어날 수 있는 예외를 처리하지는 못합니다. 이전의 메소드와 동일한 방법으로 동작합니다.\n", 211 | "\n", 212 | " * 1. 파이썬이 yield 키워드를 만난다면, 일반적인 함수 대신에 제너레이터를 만듦\n", 213 | " * 2. 데코레이션이 있기 때문에 컨텍스트 매니저는 함수 이름(open_file)을 전달 인자로서 호출\n", 214 | " * 3. contextmanager 함수는 GeneratorContextManager로 감싸진 제너레이터를 반환\n", 215 | " * 4. GeneratorContextManager는 open_file함수를 할당. 그렇기 때문에 open_file 함수를 앞으로 호출하면, 사실은 GeneratorContextManager을 호출하는 것" 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "metadata": {}, 221 | "source": [ 222 | "### 7-5. Python Context Managers and the “with” Statement (Example)\n" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 17, 228 | "metadata": {}, 229 | "outputs": [], 230 | "source": [ 231 | "from sqlalchemy import create_engine\n", 232 | "from sqlalchemy.orm import sessionmaker\n", 233 | "\n", 234 | "class SQLAlchemyDBConnection(object):\n", 235 | " \"\"\"SQLAlchemy database connection\"\"\"\n", 236 | " def __init__(self, connection_string):\n", 237 | " self.connection_string = connection_string\n", 238 | " self.session = None\n", 239 | "\n", 240 | " # with구문 진입시에 db와 connection을 하고\n", 241 | " # ORM을 사용하기 위한 session을 만들어준다.\n", 242 | " def __enter__(self):\n", 243 | " engine = create_engine(self.connection_string)\n", 244 | " Session = sessionmaker()\n", 245 | " self.session = Session(bind=engine)\n", 246 | " return self\n", 247 | "\n", 248 | " # with구문을 빠져나오기 전 session의 종료를 장한다.\n", 249 | " def __exit__(self, exc_type, exc_val, exc_tb):\n", 250 | " self.session.close()" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "```\n", 258 | "conn_str = 'mssql+pydobc://server_name/db_name?driver=SQL+Server'\n", 259 | "db = SQLAlchemyDBConnection(conn_str)\n", 260 | "with db:\n", 261 | " customer = db.session.query(Customer).filter_by(id=123).one()\n", 262 | " print(customer.name)\n", 263 | "``` " 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": {}, 269 | "source": [ 270 | "### 7-6. Async Context Manager\n", 271 | "\n", 272 | "- Context Manager는 모두 동기적으로 실행됩니다. Python 3.7부터는 Context Manager를 비동기적으로 사용할 수 있음" 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 18, 278 | "metadata": {}, 279 | "outputs": [], 280 | "source": [ 281 | "# from python 3.5\n", 282 | "\n", 283 | "class AsyncContextManager:\n", 284 | " async def __aenter__(self):\n", 285 | " await log('entering context')\n", 286 | "\n", 287 | " async def __aexit__(self, exc_type, exc, tb):\n", 288 | " await log('exiting context')" 289 | ] 290 | }, 291 | { 292 | "cell_type": "markdown", 293 | "metadata": {}, 294 | "source": [ 295 | "```\n", 296 | "# from python 3.7 \n", 297 | "\n", 298 | "from contextlib import asynccontextmanager\n", 299 | "\n", 300 | "@asynccontextmanager\n", 301 | "async def get_connection():\n", 302 | " conn = await acquire_db_connection()\n", 303 | " try:\n", 304 | " yield conn\n", 305 | " finally:\n", 306 | " await release_db_connection(conn)\n", 307 | "\n", 308 | "async def get_all_users():\n", 309 | " async with get_connection() as conn:\n", 310 | " return conn.query('SELECT ...')\n", 311 | "```" 312 | ] 313 | }, 314 | { 315 | "cell_type": "markdown", 316 | "metadata": {}, 317 | "source": [ 318 | "### 7-7. tensorflow 에서 context manager\n", 319 | "\n", 320 | "```\n", 321 | "sess = tf.Session()\n", 322 | "sess.run(...)\n", 323 | "sess.close()\n", 324 | "```\n", 325 | "\n", 326 | "```\n", 327 | "with tf.Session() as sess:\n", 328 | " sess.run(...)\n", 329 | "```\n", 330 | "\n", 331 | "- 딥러닝 라이브러리 tensorflow에서는 대부분 기능들에서 컨텍스트 매니저가 포함되어 있음\n", 332 | "- tensorflow 세션을 열고, 실행하고 리소드들이 더이상 필요하지 않을 때 해제하기 위하여 with문과 함께 컨텍스트 매니저로 실행되고 있음 (close() 메서드가 입력하지 않아도 명시적으로 실행됨)\n", 333 | "\n", 334 | "```\n", 335 | "c = tf.constant(...)\n", 336 | "sess = tf.Session()\n", 337 | "with sess.as_default():\n", 338 | " print(c.eval())\n", 339 | " \n", 340 | "with sess.as_default():\n", 341 | " print(c.eval())\n", 342 | "\n", 343 | "sess.close() \n", 344 | "```\n", 345 | "\n", 346 | "- as_default 컨텍스트 매니저는 컨텍스트를 빠져나왔을 때 세션을 닫지 않으며, 명시적으로 세션을 닫아야 함\n", 347 | "\n", 348 | "- tensorflow는 context manager를 이용해서 변수들을 그래프로 만들고, 할당하고 있는데 with 안에서 내용이 길어지다보면 너무 복잡해질 수 있음\n", 349 | "- tesorflow에서는 즉시 실행(eager execution) 모드도 제공하고 있는데, 2.0부터는 즉시 실행 모드 (tf.keras가 eager mode로 동작하여, 디버깅/프로토타이핑을 쉽게할 수 있음)\n", 350 | "\n", 351 | "```\n", 352 | "import tensorflow as tf\n", 353 | "tf.enable_eager_execution()\n", 354 | "```" 355 | ] 356 | } 357 | ], 358 | "metadata": { 359 | "kernelspec": { 360 | "display_name": "Python 3", 361 | "language": "python", 362 | "name": "python3" 363 | }, 364 | "language_info": { 365 | "codemirror_mode": { 366 | "name": "ipython", 367 | "version": 3 368 | }, 369 | "file_extension": ".py", 370 | "mimetype": "text/x-python", 371 | "name": "python", 372 | "nbconvert_exporter": "python", 373 | "pygments_lexer": "ipython3", 374 | "version": "3.5.2" 375 | } 376 | }, 377 | "nbformat": 4, 378 | "nbformat_minor": 2 379 | } 380 | -------------------------------------------------------------------------------- /day7/demo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KaggleBreak/interpy-kr/6a5e045e2ee3d1a72ea78659c8cb51b5219a9904/day7/demo.txt -------------------------------------------------------------------------------- /day7/my_functions.py: -------------------------------------------------------------------------------- 1 | ## filename:- my_functions.py 2 | 3 | def func(): 4 | return "datacamp" 5 | 6 | def _private_func(): 7 | return 7 -------------------------------------------------------------------------------- /day7/my_script.py: -------------------------------------------------------------------------------- 1 | def f(x): 2 | for _ in range(1000): 3 | x += 1 4 | return x 5 | f(12) -------------------------------------------------------------------------------- /day7/py_compatibility.ipynb: -------------------------------------------------------------------------------- 1 | {"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"py_compatibility.ipynb","version":"0.3.2","provenance":[],"collapsed_sections":[]},"kernelspec":{"name":"python2","display_name":"Python 2"}},"cells":[{"cell_type":"markdown","metadata":{"id":"KwwgQFhi8Hd9","colab_type":"text"},"source":["# 파이썬 2+3 호환 코딩"]},{"cell_type":"markdown","metadata":{"id":"6kxVnCcB8Q52","colab_type":"text"},"source":["파이썬 2와 3 환경에서 모두 실행 가능한 코드를 짜기."]},{"cell_type":"markdown","metadata":{"id":"JHWBulr9EJ9J","colab_type":"text"},"source":["## 들어가기"]},{"cell_type":"markdown","metadata":{"id":"wiKoO86xERxW","colab_type":"text"},"source":["파이썬 2와 3은 알게 모르게 큰 차이가 있다."]},{"cell_type":"code","metadata":{"id":"AjAOUj9o7dRr","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":105},"outputId":"99cc1a56-eb9e-4406-f1f5-8de184d953f8","executionInfo":{"status":"ok","timestamp":1562350288139,"user_tz":-540,"elapsed":752,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# -*- coding: utf-8 -*-\n","\n","import sys\n","\n","print '파이썬 버젼: ', sys.version # 파이썬 2\n","print '\\n'\n","print('파이썬 버젼: ', sys.version) # 파이썬 3?"],"execution_count":1,"outputs":[{"output_type":"stream","text":["파이썬 버젼: 2.7.15+ (default, Nov 27 2018, 23:36:35) \n","[GCC 7.3.0]\n","\n","\n","('\\xed\\x8c\\x8c\\xec\\x9d\\xb4\\xec\\x8d\\xac \\xeb\\xb2\\x84\\xec\\xa0\\xbc: ', '2.7.15+ (default, Nov 27 2018, 23:36:35) \\n[GCC 7.3.0]')\n"],"name":"stdout"}]},{"cell_type":"markdown","metadata":{"id":"8ZsEuUkH_bDl","colab_type":"text"},"source":["보다시피 단순한 print에서도 차이가 난다. \n","파이썬 2에서 print는 statement였다. \n","파이썬 3에서 print()는 function이다.\n","\n","print()처럼 쓰려고 해도 2개 이상 쓰자마자 tuple로 인식해 버리고 만다."]},{"cell_type":"markdown","metadata":{"id":"GSVUvjALA2HL","colab_type":"text"},"source":["파이썬 3가 배포되면서 2에서 3으로 바로 넘어가기 어려워서 였는지 2와 3 모두 쓸 수 있는 방법들이 만들어 졌다.\n","\n","~3.0.0이 배포된 게 2008년이고 이미 2.6이 있던 시기다. 그런데 벌써 10년이 넘게 매해 한 번씩은 파이썬 2를 작게라도 업데이트해준다. 슬슬 파이썬 2 지원을 끊어줬으면 한다.~"]},{"cell_type":"markdown","metadata":{"id":"gNaIQgLmEeji","colab_type":"text"},"source":["파이썬 공식 도큐먼트에 공개된 2+3 호환 코드 작성 단계는 아래와 같다.\n","1. 파이썬 2.7과 호환되면 된다.\n","2. 코드는 잘 테스트해보도록 하자.\n","3. 파이썬 2와 3의 차이를 미리 공부해 두자.\n","4. future 라이브러리를 활용하자.\n","5. pylint 툴로 코드를 점검해 보자.\n","6. caniusepython3 스크립트로 파이썬 3 사용을 막는 dependency를 찾아보자.\n","7. 앞으로도 파이썬 2와 3 모두에 쓸 수 있는 상태를 유지하자.\n","8. 변수 타입을 static하게 해줌으로써 해당 타입이 2와 3 모두에 쓰일 수 있게 하자."]},{"cell_type":"markdown","metadata":{"id":"al0BAcdVGiei","colab_type":"text"},"source":["## 함수 호환"]},{"cell_type":"markdown","metadata":{"id":"IRnOSq-1Ik20","colab_type":"text"},"source":["### print"]},{"cell_type":"code","metadata":{"id":"5ZftrtW9G6xx","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":87},"outputId":"cae9c745-92fc-45ae-831a-6c3812d4fbe5","executionInfo":{"status":"ok","timestamp":1562350288550,"user_tz":-540,"elapsed":1108,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# 파이썬 2\n","print 'Hello'\n","\n","# 파이썬 2+3\n","print('Hello')\n","\n","# 파이썬 2\n","print 'Hello', 'world'\n","\n","# 파이썬 3?\n","print('Hello', 'world')"],"execution_count":2,"outputs":[{"output_type":"stream","text":["Hello\n","Hello\n","Hello world\n","('Hello', 'world')\n"],"name":"stdout"}]},{"cell_type":"markdown","metadata":{"id":"bJUR8Of1Hh8u","colab_type":"text"},"source":["다시 print로 돌아오면 4번째 상황에서 문제가 일어남을 알 수 있다. 이것을 해결하기 위한 것이 future 라이브러리이다."]},{"cell_type":"code","metadata":{"id":"GA15bW-QIJ0j","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":35},"outputId":"162d0cb2-985b-494d-9fb2-1005dea9918b","executionInfo":{"status":"ok","timestamp":1562350288552,"user_tz":-540,"elapsed":1073,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# 파이썬 2+3\n","from __future__ import print_function\n","\n","print('Hello', 'world')"],"execution_count":3,"outputs":[{"output_type":"stream","text":["Hello world\n"],"name":"stdout"}]},{"cell_type":"markdown","metadata":{"id":"CUr7VDW5Idvm","colab_type":"text"},"source":["무사히 print()가 불러와졌다!\n","\n","다른 상황들을 살펴보자."]},{"cell_type":"markdown","metadata":{"id":"kIav61TeInAb","colab_type":"text"},"source":["### raise"]},{"cell_type":"code","metadata":{"id":"l2Zpie7dIjv0","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":167},"outputId":"5da9d906-8e60-49ec-d513-68dacc1cd75a","executionInfo":{"status":"error","timestamp":1562350289023,"user_tz":-540,"elapsed":1493,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# 파이썬 2\n","raise ValueError, \"에러가 일어나 버렸구나.\""],"execution_count":4,"outputs":[{"output_type":"error","ename":"ValueError","evalue":"ignored","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[0;32mraise\u001b[0m \u001b[0mValueError\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[0m","\u001b[0;31mValueError\u001b[0m: 에러가 일어나 버렸구나."]}]},{"cell_type":"code","metadata":{"id":"VcuUx4LfJAJ9","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":167},"outputId":"bdef0871-ff15-4b53-8498-59d3763cd2b8","executionInfo":{"status":"error","timestamp":1562350300420,"user_tz":-540,"elapsed":757,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# 파이썬 2+3\n","raise ValueError(\"에러가 일어나 버렸어.\")"],"execution_count":5,"outputs":[{"output_type":"error","ename":"ValueError","evalue":"ignored","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[0;32mraise\u001b[0m \u001b[0mValueError\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[0m","\u001b[0;31mValueError\u001b[0m: 에러가 일어나 버렸어."]}]},{"cell_type":"markdown","metadata":{"id":"zD1wTUCxKlgQ","colab_type":"text"},"source":["### exception"]},{"cell_type":"code","metadata":{"id":"C4T7oDTHKeVA","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":132},"outputId":"f1d4ab46-ffba-4bc2-c37e-6cd346bb75f3","executionInfo":{"status":"error","timestamp":1562350303110,"user_tz":-540,"elapsed":744,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# 파이썬 2\n","try:\n"," ...\n","except ValueError, e:\n"," ..."],"execution_count":6,"outputs":[{"output_type":"error","ename":"SyntaxError","evalue":"ignored","traceback":["\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m ...\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"]}]},{"cell_type":"code","metadata":{"id":"krtejMZ2KlOf","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":132},"outputId":"bfe74c59-2235-49af-b001-41404442c34b","executionInfo":{"status":"error","timestamp":1562350305509,"user_tz":-540,"elapsed":728,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# 파이썬 2+3\n","try:\n"," ...\n","except ValueError as e:\n"," ..."],"execution_count":7,"outputs":[{"output_type":"error","ename":"SyntaxError","evalue":"ignored","traceback":["\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m ...\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"]}]},{"cell_type":"markdown","metadata":{"id":"zVjg0x3MK3Yz","colab_type":"text"},"source":["### division"]},{"cell_type":"code","metadata":{"id":"i28hiDx_K5Mr","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":53},"outputId":"e5b04c5a-cd3f-4af1-e54f-897f4b5e4d8e","executionInfo":{"status":"ok","timestamp":1562350307708,"user_tz":-540,"elapsed":893,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# 파이썬 2\n","print(2 / 3)\n","\n","# 파이썬 2+3\n","print(2 // 3)"],"execution_count":8,"outputs":[{"output_type":"stream","text":["0\n","0\n"],"name":"stdout"}]},{"cell_type":"code","metadata":{"id":"fzPJdb6cLPJ0","colab_type":"code","colab":{}},"source":["# 파이썬 3\n","3 / 2 # 파이썬 3 환경에서는 1.5로 true divison이 실행됨."],"execution_count":0,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"zG2G-VumLOwA","colab_type":"text"},"source":[""]},{"cell_type":"code","metadata":{"id":"KS6JXA75L4V7","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":35},"outputId":"eeac1a8b-b999-42fa-f60a-8aeb85ee8bcb","executionInfo":{"status":"ok","timestamp":1562350309731,"user_tz":-540,"elapsed":741,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["# 파이썬 2+3\n","from __future__ import division\n","\n","3 / 2"],"execution_count":9,"outputs":[{"output_type":"execute_result","data":{"text/plain":["1.5"]},"metadata":{"tags":[]},"execution_count":9}]},{"cell_type":"markdown","metadata":{"id":"-JDkcZOxMlhQ","colab_type":"text"},"source":["이외에도 `long`이나 `metaclass`, `dict iteration`, `unicode` 등 다양한 곳에서 차이가 있다.\n","\n","하지만 모든 것을 커버할 수 없으니 **필요하다면** 검색해보길 추천한다.\n","\n","진짜로 거의 모든 영역에서 파이썬 2와 3은 충돌한다."]},{"cell_type":"markdown","metadata":{"id":"Cfsed1UcNWZV","colab_type":"text"},"source":["### 사용 라이브러리\n","- future: (2 → 3) 파이썬 3를 구현할 수 있다. 어째서인지 \\_\\_future__로 불러와야 한다.\n","- past: (3 → 2) 파이썬 2를 구현할 수 있다.\n","- builtins: 파이썬 빌트인 identifiers를 불러오므로 버젼과 상관없이 사용이 가능하다.\n","\n","아래 라이브러리는 파이썬 3에는 있지만 파이썬 2에는 없다. 그래도 설치해서 사용이 가능하다고 한다.\n","\n","- enum\n","- singledispatch: `functool` 안에 있었다.\n","- pathlib"]},{"cell_type":"markdown","metadata":{"id":"DXUSWkpgOpZW","colab_type":"text"},"source":["## Import 호환"]},{"cell_type":"markdown","metadata":{"id":"fwDLT2muO3RX","colab_type":"text"},"source":["Exception를 활용하여 환경에 따라 맞춤 라이브러리를 불러올 수 있다. (`ImportError` 회피)\n","\n","그러나 환경에 따라 기능이 같더라도 다른 라이브러리일 수 있기 때문에 `as`로 이름을 지정해주면 파이썬 2와 3에 상관없이 사용할 수 있다."]},{"cell_type":"code","metadata":{"id":"dbsI1ke1O5Q6","colab_type":"code","colab":{}},"source":["try:\n"," import urllib.request as urllib_request # 파이썬 3\n","except:\n"," import urllib2 as urllib_request # 파이썬 2"],"execution_count":0,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"CV6m-0vyThuG","colab_type":"text"},"source":["## 파이썬 2 내장함수 제거"]},{"cell_type":"markdown","metadata":{"id":"d4BXgB4GTmpM","colab_type":"text"},"source":["파이썬 3는 파이썬 2의 내장함수(builtin function) 중 12개를 지원하지 않는다고 한다. \n","실수로라도 해당 빌트인을 쓰지 않기 위해서 아래 코드를 쓰도록 한다."]},{"cell_type":"code","metadata":{"id":"0c6eOkQUUTgJ","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":325},"outputId":"cac30039-6079-4cd0-d5ec-c4e4dd090dbe","executionInfo":{"status":"error","timestamp":1562350312956,"user_tz":-540,"elapsed":981,"user":{"displayName":"MANNSOO HONG","photoUrl":"https://lh5.googleusercontent.com/-kDJT9czI1YY/AAAAAAAAAAI/AAAAAAAAACI/Xuh1tSNF6GI/s64/photo.jpg","userId":"17957710327556825549"}}},"source":["from future.builtins.disabled import *\n","\n","apply()"],"execution_count":11,"outputs":[{"output_type":"error","ename":"NameError","evalue":"ignored","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[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mfuture\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuiltins\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdisabled\u001b[0m \u001b[0;32mimport\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;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mapply\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[0m","\u001b[0;32m/usr/local/lib/python2.7/dist-packages/future/builtins/disabled.pyc\u001b[0m in \u001b[0;36mdisabled\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[0mno\u001b[0m \u001b[0mlonger\u001b[0m \u001b[0ma\u001b[0m \u001b[0mbuiltin\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mPython\u001b[0m \u001b[0;36m3.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 56\u001b[0m '''\n\u001b[0;32m---> 57\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mNameError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'obsolete Python 2 builtin {0} is disabled'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\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[0m\u001b[1;32m 58\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mdisabled\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 59\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;31mNameError\u001b[0m: obsolete Python 2 builtin apply is disabled"]}]},{"cell_type":"markdown","metadata":{"id":"GoMfqGHJUbve","colab_type":"text"},"source":[""]},{"cell_type":"markdown","metadata":{"id":"d3ziGON2QGhp","colab_type":"text"},"source":["## 자동 호환"]},{"cell_type":"markdown","metadata":{"id":"d_q_1URTQIi6","colab_type":"text"},"source":["~솔직히 하나하나 다 따져가면서 코드를 짜고 싶지 않다.~\n","\n","자동으로 파이썬 2를 3으로 바꿔주는 프로그램들이 있다."]},{"cell_type":"markdown","metadata":{"id":"WyETOaLERTvg","colab_type":"text"},"source":["### 2to3\n","[2.7: Automated Python 2 to 3 code translation](https://docs.python.org/2.7/library/2to3.html)\n","\n","미리 저장해둔 fixer로 파이썬 2 코드를 3로 변환시켜준다. \n","1:1 대응이기 때문에 유연성이 떨어질 수 있다. \n","커맨드라인에 `2to3`하고 파일명을 적어주자.\n","\n","파이썬이 공식으로 지원하는 프로그램이다.\n","\n","[lib2to3](https://github.com/python/cpython/tree/master/Lib/lib2to3)라는 라이브러리로 API를 제공한다."]},{"cell_type":"markdown","metadata":{"id":"ZAtLR5WcSCa9","colab_type":"text"},"source":["### Python-modernize\n","`lib2to3`를 랩핑하여 만들었다.\n","\n","[Github](https://github.com/python-modernize/python-modernize)"]}]} --------------------------------------------------------------------------------