#!/usr/bin/env python # coding: utf-8 # ## 4.1 개요 # ## 4.2 22가지 프로그래밍 지름길 # ### 4.2.1 필요하다면 코드를 여러 줄에 걸쳐서 작성한다 # In[1]: my_str = 'I am Hen-er-y the Eighth,' ' I am!' print(my_str) # In[3]: my_str = 'I am Hen-er-y the Eighth,' \ ' I am!' my_str # In[4]: my_str = ('I am Hen-er-y the Eighth, ' 'I am! I am not just any Henry VIII, ' 'I really am!') my_str # In[5]: a = 10, 5 type(a) # In[6]: side1, side2 = a # In[8]: side1 # In[9]: side2 # In[4]: side1, side2 = 10, 5 length_of_hypotenuse = ( (side1 * side1 + side2 * side2) ** 0.5 ) length_of_hypotenuse # In[11]: side1, side2 = 10, 5 length_of_hypotenuse = (side1 * side1 + side2 * side2) \ ** 0.5 length_of_hypotenuse # ### 4.2.2 for 루프는 현명하게 사용한다. # In[5]: beat_list = ['John', 'Paul', 'George', 'Ringo'] for i in range(len(beat_list)): print(beat_list[i]) # In[6]: beat_list = ['John', 'Paul', 'George', 'Ringo'] for guy in beat_list: print(guy) # In[7]: beat_list = ['John', 'Paul', 'George', 'Ringo'] for i, name in enumerate(beat_list, 1): print(i, '. ', name, sep='') # ### 4.2.3 조합 대입 연산자를 이해한다. (예: +=) # # ![](./images_skill_up/4-2.PNG) # In[8]: s1 = s2 = 'A string.' s1 += '...with more stuff!' print('s1:', s1) print('s2:', s2) # In[9]: a_list = b_list = [10, 20] a_list += [30, 40] print('a_list:', a_list) print('b_list:', b_list) # In[10]: str_list = [] n = ord('a') for i in range(n, n + 26): str_list += chr(i) alphabet_str = ''.join(str_list) alphabet_str # ### 4.2.4 다중 대입을 사용한다 # In[11]: a = b = c = d = e = 0 # In[12]: a is b # ### 4.2.5 튜플 대입을 사용한다 # In[13]: a = 1 b = 0 # In[14]: a, b = 1, 0 # In[15]: a = 4, 8, 12 # a는 이제 3개 값을 지닌 튜플이다. a # In[17]: a, b = 10, 20 temp = a # a 기존 값 보존 a = a + b # a에 신규 값 설정 b = temp # b에 a 기존 값 저장 print(a, b) # In[18]: a, b = 10, 20 a, b = a + b, a print(a, b) # In[16]: def fibo(n): a, b = 1, 0 while a <= n: print(a, end=' ') a, b = a + b, a fibo(10) # In[19]: x, y = 1, 25 print(x, y) # 1 25 출력 x, y = y, x print(x, y) # 25 1 출력 # In[21]: a, b, c = [1, 2, 3] # In[22]: print(a, b, c) # ### 4.2.6 고급 튜플 대입을 사용한다 # In[20]: tup = 10, 20, 30 # 패킹 (Packing) a, b, c = tup # 언패킹 (Unpacking) print(a, b, c) # 10, 20, 30 출력 # In[21]: tup = 10, 20, 30 a, b = tup # 에러: 언팩 대상 값이 너무 많음 # In[24]: my_list = [3] # In[25]: my_tup = (3) print(type(my_tup)) # In[26]: my_tup = (3,) # 한 항목 3을 가진 튜플 만들기 print(type(my_tup)) # In[12]: a, *b = 2, 4, 6, 8 print(a, b) # In[13]: a, *b, c = 10, 20, 30, 40, 50 print(a, b, c) # In[29]: big, bigger, *many = 100, 200, 300, 400, 500, 600 # In[30]: print(big, bigger, many, sep='\n') # ### 4.2.7 리스트와 문자열 '곱하기'를 사용한다 # In[31]: my_list = [0] * 10000 len(my_list) # In[32]: my_list = 1999 * [12] len(my_list) # In[33]: trip_list = [1, 2, 3] * 100 len(trip_list) # In[34]: divider_str = '_' * 40 divider_str # ### 4.2.8 다중 값을 반환한다 # In[35]: def double_me(n): n *= 2 a = 10 double_me(a) print(a) # a 값이 두배가 되지 않는다!! # In[36]: def double_me(n): return n * 2 a = 10 a = double_me(a) print(a) # In[37]: def quad(a, b, c): determin = (b * b - 4 * a * c) ** .5 x1 = (-b + determin) / (2 * a) x2 = (-b - determin) / (2 * a) return x1, x2 # In[38]: x1, x2 = quad(1, -1, -1) # In[39]: x = quad(1, -1, -1) x # ### 4.2.9 루프와 else 키워드를 사용한다 # In[43]: def find_divisor(n, max): for i in range(2, max + 1): if n % i == 0: print(i, 'divides evenly into', n) break else: # break를 만나서 일찍 빠져나오지 않는 한 루프 종료시 수행된다. print('No divisor found') # In[44]: find_divisor(49, 6) # In[45]: find_divisor(49, 7) # ### 4.2.10 불리언과 'not'의 이점을 활용한다 # In[43]: my_str = '' while True: if len(my_str) == 0: break # In[44]: while True: if not my_str: break # ### 4.2.11 문자열은 문자의 나열로 다룬다 # In[16]: test_str = input('Enter test string: ') a_list = [c.upper() for c in test_str if c.isalnum()] print(a_list) print(a_list == a_list[::-1]) # ### 4.2.12 replace를 사용하여 문자를 제거한다 # In[46]: s = '1 / 2' s = s.replace(' ', '') s # In[47]: s = 'same day' a_list = [c for c in s if c not in 'aeiou'] s = ''.join(a_list) s # In[19]: s = 'same day' s = s.replace('a', '').replace('e', '').replace('i', '').replace('o', '').replace('u', '') s # ### 4.2.13 필요 없는 루프는 사용하지 않는다 # In[20]: def calc_triangle_num(n): s = 0 for i in range(n + 1): s += i return s calc_triangle_num(10) # In[48]: def calc_triangle_num(n): return sum(range(n + 1)) calc_triangle_num(10) # In[21]: def get_avg(a_list): s = 0 for i in a_list: s += i return s / len(a_list) get_avg([10, 20, 30, 40]) # In[22]: def get_avg(a_list): return sum(a_list) / len(a_list) get_avg([10, 20, 30, 40]) # ### 4.2.14 연결된(chained) 비교 연산자를 사용한다 # In[50]: x = 55 if 0 < x and x < 100: print('x is in range.') # In[51]: if 0 < x < 100: # 연결된(chained) 비교 연산자 사용 print('x is in range.') # In[52]: a, b, c = 5, 10, 15 if 0 < a <= c > b > 1: print('All these comparisons are true!') print('c is equal or greater than all the rest!') # In[53]: a = b = c = d = e = 100 if a == b == c == d == e: print('All the variables are equal to each other.') # In[54]: a_list = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ,1 ,1] if min(a_list) == max(a_list): print('All the elements are equal to each other.') # ### 4.2.15 함수 테이블(리스트, 딕셔너리)로 'switch'를 모방한다 # In[23]: n = 1 def test(name='init'): print('hello,', name) do_plot = do_highlow_plot = do_volume_subplot = do_movingavg_plot = test stockdf = 'insuk' if n == 1: do_plot(stockdf) elif n == 2: do_highlow_plot(stockdf) elif n == 3: do_volume_subplot(stockdf) elif n == 4: do_movingavg_plot(stockdf) # In[25]: n = 1 fn = [do_plot, do_highlow_plot, do_volume_subplot, do_movingavg_plot][n - 1] fn(stockdf) # 함수 호출 # In[26]: n = 1 f_list = [do_plot, do_highlow_plot, do_volume_subplot, do_movingavg_plot] fn = f_list[n - 1] fn(stockdf) # 함수 호출 # In[27]: load_fn = save_fn = exit_fn = update_fn = test menu_dict = {'load':load_fn, 'save':save_fn, 'exit':exit_fn, 'update':update_fn} selector = 'exit' (menu_dict[selector])() # 함수 호출 # ### 4.2.16 is 연산자는 정확하게 사용한다 # In[28]: a = 'cat' b = 'cat' a == b # 반드시 True 반환 # In[29]: s1 = 'I am what I am and that is all that I am.' s2 = 'I am what I am' + ' and that is all that I am.' s1 == s2 # In[30]: s1 is s2 # In[61]: def my_function(): return None a_value = my_function() if a_value is None: # 이곳에 if a_value == None 은 불가!!! # None이 반환되면 특별한 행동을 취해라. print('a_value 함수의 반환값은 None이다.') # ### 4.2.17 단일 행 for 루프를 사용한다 # In[62]: for i in range(10): print(i, end=' ') # ### 4.2.18 여러 문장을 하나의 행으로 줄인다 # In[63]: for i in range(5): n=i*2; m = 5; print(n+m, end=' ') # In[64]: a = 1; b = 2; c = a + b; print(c) # ### 4.2.19 단일 행 if/then/else 문을 작성한다 # In[65]: turn = 0 if turn % 2: cell = 'X' else: cell = 'O' cell # In[66]: cell = 'X' if turn % 2 else 'O' cell # ### 4.2.20 range와 함께 Enum을 생성한다 # In[67]: red = 0 blue = 1 green = 2 black = 3 white = 4 print(red, blue, green, black, white) # In[68]: red, blue, green, black, white = range(5) print(red, blue, green, black, white) # In[69]: red, blue, green, black, white = range(1, 6) print(red, blue, green, black, white) # In[32]: import enum help(enum) # In[34]: from enum import Enum class Color(Enum): red = 1 blue = 2 # In[37]: a = Color.red b = Color.blue print(a, ":", a.value) # ### 4.2.21 IDLE안에서 비효율적인 print 함수 사용을 줄인다 # - IDLE: Integrated DeveLopment Environment (통합개발환경) # - Jupyter Notebook # - Pycharm # - Visual Studio Code # In[38]: for i in range(20): for j in range(40): print('*', end='') print() # In[39]: row_of_asterisks = '*' * 40 for i in range(20): print(row_of_asterisks) # In[40]: row_of_asterisks = '*' * 40 s = '' for i in range(20): s += row_of_asterisks + '\n' print(s) # In[41]: row_of_asterisks = '*' * 40 list_of_str = [] for i in range(20): list_of_str.append(row_of_asterisks) print('\n'.join(list_of_str)) # In[42]: print('\n'.join(['*' * 40] * 20)) # ### 4.2.22 큰 번호 안에 언드스코어(_)를 넣는다 # In[76]: CEO_salary = 1500000 # In[77]: CEO_salary = 1_500_000 CEO_salary # ### [추가] 레퍼런스 카운트 이해 # In[78]: x = y = z = 100 # # In[79]: print(x is y) print(y is z) # In[80]: del x # # In[81]: y = 200 z = 300 # # ### 4.3.1 윈도 기반 시스템에서 실행하기 # In[47]: get_ipython().system('python test.py') # In[46]: get_ipython().system('python -V') # ### 4.3.2 macOS 시스템에서 실행하기 # ### 4.3.3 pip 혹은 pip3로 패키지 내려받기 # In[48]: get_ipython().system('conda install numpy') # In[49]: get_ipython().system('pip install numpy') # ## 4.4 Doc Strings 작성하고 사용하기 # In[50]: def quad(a, b, c): '''Quadratic Formula function. This function applies the Quadratic Formula to determine the roots of x in a quadratic equation of the form ax^2 + bx + c = 0. ''' determin = (b * b - 4 * a * c) ** .5 x1 = (-b + determin) / (2 * a) x2 = (-b - determin) / (2 * a) return x1, x2 # In[51]: help(quad) # In[52]: def quad(a, b, c): '''Quadratic Formula function. This function applies the Quadratic Formula to determine the roots of x in a quadratic equation of the form ax^2 + bx + c = 0. ''' determin = (b * b - 4 * a * c) ** .5 x1 = (-b + determin) / (2 * a) x2 = (-b - determin) / (2 * a) return x1, x2 # In[53]: help(quad) # In[54]: get_ipython().system('python -m pydoc queens') # ## 4.5 패키지 탑재하기 # In[55]: import math help(math) # In[56]: math.sqrt(2) # In[57]: math.atan(1) * 4 # In[58]: math.pi # - 별칭 (alias) # In[59]: import matplotlib.pyplot as plt # In[60]: from math import pi print(pi) # In[61]: from math import * print(pi) print(sqrt(2)) # ## 4.6 파이썬 패키지의 가이드 투어? # ![](./tables_skill_up/t0401-1.PNG) # ![](./tables_skill_up/t0401-2.PNG) # ## 4.7 일급 객체인 함수 # - 일급 객체는 OOP에서 사용되는 개념 중 하나로 아래의 조건을 만족하는 객체를 의미함 # # - 1. 변수 혹은 데이터 구조(자료구조) 안에 담을 수 있어야 한다. # - 2. 매개변수로 전달할 수 있어야 한다. # - 3. 리턴값으로 사용될 수 있어야 한다. # - https://tibetsandfox.tistory.com/8 # In[1]: def avg(a_list): '''리스트 항목들의 평균값을 반환한다''' x = (sum(a_list) / len(a_list)) print('The average is:', x) return x # In[2]: type(avg) # In[3]: help(avg) # In[4]: def new_func(a_list): return (sum(a_list) / len(a_list)) old_avg = avg avg = new_func # In[5]: old_avg([4, 6]) # In[6]: def func_info(func): print('Function name:', func.__name__) print('Function documentation:') help(func) # In[7]: func_info(old_avg) # ## 4.8 가변길이 매개변수 # # ### 4.8.1 *args 리스트 # In[10]: def my_var_func(*args): print('The number of args is', len(args)) print('The type of args is', type(args)) for item in args: print(item) my_var_func(10, 20, 30, 40) # In[11]: def avg(*args): return sum(args)/len(args) avg(11, 22, 33) # In[12]: avg(1, 2) # In[13]: def avg(units, *args): print (sum(args)/len(args), units) avg('inches', 11, 22, 33) # In[14]: ls = [1, 2, 3] # 언팩된 리스트 print(*ls) # 언팩 버전 출력하기 # In[15]: print(ls) # 패킹된 버전 출력하기 (일반 리스트) # ### 4.8.2 **kwargs 리스트 # In[23]: print(10, 20, 30, end='.', sep=',') # In[26]: def pr_named_vals(**kwargs): print("The length of kwargs is", len(kwargs)) print("The type of kwargs is", type(kwargs)) for k in kwargs: print(k, ':', kwargs[k]) # In[27]: pr_named_vals(a=10, b=20, c=30) # In[30]: def pr_vals_2(*args, **kwargs): for i in args: print(i) for k in kwargs: print(k, ':', kwargs[k]) # In[31]: pr_vals_2(1, 2, 3, -4, a=100, b=200) # ## 4.9 데코레이터(Decorator)와 함수 프로파일러(Profiler) # - 데코레이터: 기존 함수가 그대로 동작하면서 추가 문장이 더 실행되는 래퍼 함수(Wrapper Function) # ![](./images_skill_up/4-3.PNG) # - 인수처리를 못하는 래퍼 함수 만들기 # In[50]: import time def make_timer_wrapper(func): def wrapper(): t1 = time.time() ret_val = func() t2 = time.time() print('소요 시간 :', t2 - t1) return ret_val return wrapper # In[51]: def count_nums(): s = 0 for i in range(10): for j in range(1000): s += i * j return s # In[52]: count_nums = make_timer_wrapper(count_nums) # In[55]: count_nums() # - 인수처리 가능한 래퍼 함수 만들기 # In[63]: import time def make_timer_wrapper(func): def wrapper(*args, **kwargs): t1 = time.time() ret_val = func(*args, **kwargs) t2 = time.time() print('소요 시간 :', t2 - t1) return ret_val return wrapper # In[60]: def count_nums(n): s = 0 for i in range(n): for j in range(1000): s += i * j return s # In[61]: count_nums = make_timer_wrapper(count_nums) # In[62]: count_nums(10) # - 데코레이터로 위 복잡한 과정을 편리하게 만들기 # In[ ]: @make_timer_wrapper def count_nums(n): s = 0 for i in range(n): for j in range(1000): s += i * j return s # In[64]: count_nums(10) # - 다른 예제 # In[65]: def decoratorExample(func): def wrapFunc(*args, **kargs): print("Start", func.__name__) func(*args, **kargs) print("End", func.__name__) return wrapFunc @decoratorExample def test(a, b, c): print("Variables :", a,b,c) test("1", 2, c="345") # In[67]: def smart_divide(func): def inner(a, b): print("I am going to divide", a, "and", b) if b == 0: print("Whoops! cannot divide") return return func(a, b) return inner @smart_divide def divide(a, b): print(a / b) # In[68]: divide(2, 5) # In[69]: divide(2, 0) # ## 4.10 제너레이터 # # ### 4.10.1 이터레이터란 무엇인가? # - 이터레이터 객체 정의 # - 가상의 Sequence 자료를 지니고 있으면서 내부적으로 \_\_next\_\_(self) 메직 메소드를 지니고 있는 객체 # - 내부적으로 지닌 Sequence 자료를 차례로 반환 # - next() 내장 함수에 대응됨 # - next() 내장 함수 호출할 때 마다 각 원소 반환 # - next() 내장 함수 호출할 때 더 이상 자료를 념겨줄 수 없다면 StopIteration 예외 발생 # - 이터레이터 객체의 메모리 효율성 # - 반복자가 원 객체의 원소들을 복사하여 지니고 있지 않음. # - 메모리 효율성! # # - 임의의 객체에 대해 반복자 객체를 얻어오는 방법 # - iter(o) 내장 함수 # - 객체 o의 반복자 객체를 반환한다. # # - 집합적 객체 A --> iter(A) --> 반복자 객체 B 반환 --> next(B) --> 집합적 자료형 안의 내부 원소를 하나씩 반환 # # In[1]: I = iter([1, 2, 3]) print(I) # In[2]: print(next(I)) print(next(I)) print(next(I)) print(next(I)) # - 리스트 객체에 반복자와 StopIteration 예외를 동시에 활용한 예 # In[3]: def f(x): print(x + 1) t = iter([1, 2, 3]) while True: try: x = next(t) except StopIteration: break f(x) # - 리스트 객체에 대해 일반적인 for ~ in 반복 문 사용예 # - for 문이 반복할 때 마다 이터레이터 객체에 next() 내장 함수가 자동으로 호출되어 순차적으로 각 객체에 접근 # - StopIteration이 발생하면 for ~ in 구문 자동 정지 # In[4]: def f(x): print(x + 1) for x in [1, 2, 3]: f(x) # In[5]: iter1 = reversed([1, 2, 3, 4]) print(iter1) # In[6]: print(list(iter1)) # In[7]: iter1 = reversed([1, 2, 3, 4]) for i in iter1: print(i, end=' ') # In[8]: def f(x): print(x + 1) t = iter([1, 2, 3]) for x in t: f(x) # In[9]: def f(x): print(x + 1) for x in iter([1, 2, 3]): f(x) # In[10]: def f(x): print(x + 1) for x in iter((1, 2, 3)): f(x) # #### 사전의 반복자 # - 사전에 대해 for ~ in 구문은 키에 대해 반복한다. # - iter(d) 또는 iter(d.keys()) 사용 # In[11]: d = {'one':1, 'two':2, 'three':3, 'four':4, 'five':5} for key in d: print(key, d[key]) # In[12]: d = {'one':1, 'two':2, 'three':3, 'four':4, 'five':5} for key in iter(d): print(key, d[key]) # In[13]: print(type(d.keys())) print(type(iter(d.keys()))) # In[14]: next(d.keys()) # In[15]: next(iter(d.keys())) # In[16]: for key in d.keys(): # 키에 대한 반복자, iter(d.keys()) 가 반환한 반복자에 대해 __next__(self) 함수가 순차적으로 불리워짐 print(key, end=" ") print() for key in iter(d.keys()): # 키에 대한 반복자, iter(d.keys()) 가 반환한 반복자에 대해 __next__(self) 함수가 순차적으로 불리워짐 print(key, end=" ") # In[17]: keyset = iter(d) print(next(keyset)) # 반복자 객체는 항상 next() 내장 함수에 값을 반환할 수 있음 (내부적으로 __next__(self) 호출) for key in keyset: # keyset 반복자에 대해 next() 메소드가 순차적으로 호출됨 print(key, end=" ") # In[18]: print(type(d.values())) print(type(iter(d.values()))) # In[19]: for key in d.values(): # 키에 대한 반복자, iter(d.keys()) 가 반환한 반복자에 대해 __next__(self) 함수가 순차적으로 불리워짐 print(key, end=" ") print() for key in iter(d.values()): # 키에 대한 반복자, iter(d.keys()) 가 반환한 반복자에 대해 __next__(self) 함수가 순차적으로 불리워짐 print(key, end=" ") # In[20]: print(type(d.items())) print(type(iter(d.items()))) # In[24]: for key, value in d.items(): print(key, value, end=" ") print() for key, value in iter(d.items()): print(key, value, end=" ") # #### 파일 객체의 반복자 # - 파일 객체는 그 자체가 반복자임 # - next() 함수에 의해 각 라인이 순차적으로 읽혀짐 # In[26]: f = open('readme.txt') print(next(f)) for line in f: # f.next() 가 순차적으로 호출됨 print(line) # ### 4.10.2 제너레이터 소개 # - 아래 함수 f()는 자신의 인수 및 내부 로컬 변수로서 a, b, c, d를 지니고 있다. # - 이러한 a, b, c, d 변수들은 함수가 종료되고 반환될 때 모두 사라진다. # - 발생자는 f()와 같이 함수가 (임시로) 종료될 때 내부 로컬 변수가 메모리에서 해제되는 것을 막고 다시 함수가 호출 될 때 이전에 수행이 종료되었던 지점 부터 계속 수행이 가능하도록 구현된 함수이다. # In[27]: def f(a, b): c = a * b d = a + b return c, d x, y = f(1, 2) print(x, y) # - 발생자(Generator) # - (중단됨 시점부터) 재실행 가능한 함수 # ![](./images_skill_up/4-4.PNG) # - yield 키워드 # - return 대신에 yield에 의해 값을 반환하는 함수는 발생자이다. # - yield는 return과 유사하게 임의의 값을 반환하지만 함수의 실행 상태를 보존하면서 함수를 호출한 쪽으로 복귀시켜준다. # # - 발생자는 곧 반복자이다!!! # - 즉, 발생자에게 next() 호출이 가능하다. # In[28]: def f(a, b): c = a * b d = a + b yield c, d g = f(1, 2) x, y = next(g) print(x, y) x, y = next(g) print(x, y) # In[ ]: def f(a, b): for _ in range(2): c = a * b d = a + b yield c, d g = f(1, 2) x, y = next(g) print(x, y) x, y = next(g) print(x, y) # - 발생자 함수와 일반 함수의 차이점 # - 일반 함수는 함수가 호출되면 그 함수 내부에 정의된 모든 일을 마치고 결과를 반환함 # - 발생자 함수는 함수 내에서 수행 중에 중간 결과 값을 반환할 수 있음 # # - 발생자가 유용하게 사용되는 경우 # - 함수 처리의 중간 결과를 다른 코드에서 사용해야 할 경우 # - 즉, 모든 결과를 한꺼번에 반환 받는 것이 아니라 함수 처리 중에 나온 중간 결과를 받아서 사용해야 할 경우 # - 시퀀스 자료형을 효율적으로 만들고자 하는 경우 # In[30]: def print_evens(): for n in range(2, 11, 2): print(n) print_evens() # In[35]: def make_evens_gen(): for n in range(2, 11, 2): yield n my_gen = make_evens_gen() # In[36]: next(my_gen) # In[37]: next(my_gen) # In[38]: next(my_gen) # In[39]: my_gen = make_evens_gen() # 다시 시작 next(my_gen) # In[40]: next(my_gen) # In[41]: next(my_gen) # In[42]: my_gen = make_evens_gen() # 다시 시작 # In[43]: next(my_gen) # In[44]: next(my_gen) # In[45]: next(my_gen) # In[46]: next(make_evens_gen()) # In[47]: next(make_evens_gen()) # In[48]: next(make_evens_gen()) # In[49]: for i in make_evens_gen(): print(i, end=' ') # In[50]: my_gen = make_evens_gen() for i in my_gen: print(i, end=' ') # In[52]: my_gen = make_evens_gen() a_list = list(my_gen) a_list # In[53]: a_list = list(my_gen) # 앗! 다시 초기화(reset)를 안했군! a_list # In[54]: a_list = list(make_evens_gen()) a_list # In[59]: def make_fibo_gen(n): a, b = 1, 1 while a <= n: yield a a, b = a + b, a # In[61]: my_fibo_gen = make_fibo_gen(10) print(my_fibo_gen) print(list(my_fibo_gen)) # In[62]: n = int(input('Enter number: ')) if n in make_fibo_gen(n): print('number is a Fibonacci. ') else: print('number is not a Fibonacci. ') # In[63]: n = int(input('Enter number: ')) my_fibo_gen = make_fibo_gen(n) if n in my_fibo_gen: print('number is a Fibonacci. ') else: print('number is not a Fibonacci. ') # - 제너레이터의 활용 # In[64]: def generate_ints(N): for i in range(N): yield i # In[65]: gen = generate_ints(3) # 발생자 객체를 얻는다. generate_ints() 함수에 대한 초기 스택 프레임이 만들어지나 실행은 중단되어 있는 상태임 print(gen) # print(gen.next()) # print(gen.next()) # print(gen.next()) # print(gen.next()) print(next(gen)) # 발생자 객체는 반복자 인터페이스를 가진다. 발생자의 실행이 시작됨. yield에 의해 값 반환 후 실행이 중단됨 print(next(gen)) # 발생자 실행 재개. yield에 의해 값 반환 후 다시 중단 print(next(gen)) # 발생자 실행 재개. yield에 의해 값 반환 후 다시 중단 print(next(gen)) # 발생자 실행 재개. yield에 의해 더 이상 반환할 값이 없다면 StopIteration 예외를 던짐 # - 위와 같은 세부 동작 방식을 이용하여, 다음과 같이 for ~ in 구문에 적용할 수 있다. # In[66]: for i in generate_ints(5): print(i, end=" ") # - 리스트 내포 vs. 발생자 # - 리스트 내포는 리스트 객체의 새로운 생성. 즉, 메모리를 실제로 점유하면서 생성됨 # In[67]: a = [k for k in range(100) if k % 5 == 0] print(a) type(a) # - 리스트 내포 구문에 []가 아니라 () 사용 # - 리스트 대신에 발생자 생성 # - 즉, 처음부터 모든 원소가 생성되지 않고 필요한 시점에 각 원소가 만들어짐 # - 메모리를 보다 효율적으로 사용할 수 있음 # In[68]: a = (k for k in range(100) if k % 5 == 0) print(a) type(a) # In[69]: print(next(a)) print(next(a)) print(next(a)) for i in a: print(i, end=" ") # - 아래 예는 sum 내장 함수에 발생자를 넣어줌 # - sum을 호출하는 시점에는 발생자가 아직 호출되기 직전이므로 각 원소들은 아직 존재하지 않는다. # - sum 내부에서 발생자가 지니고 있는 next() 함수를 호출하여 각 원소들을 직접 만들어 활용한다. # - 메모시 사용 효율이 높다. # In[71]: a = (k for k in range(100) if k % 5 == 0) print(sum(a)) # #### 발생자의 실제 활용 예 1 - 피보나치 수열 # In[72]: def fibonacci(a = 1, b = 1): while 1: yield a a, b = b, a + b for k in fibonacci(): # 발생자를 직접 for ~ in 구문에 활용 if k > 100: break print(k, end=" ") # #### 발생자의 활용 예 2 - 홀수 집합 만들기 # In[74]: def odds(limit=None): k = 1 while not limit or limit >= k: yield k k += 2 for k in odds(20): print(k, end=" ") print() print(list(odds(20))) # list() 내장 함수가 발생자를 인수로 받으면 해당 발생자의 next()를 매번 호출하여 각 원소를 얻어온다. # ## 4.11 커맨드-라인 인수 접근하기 # ![](./images_skill_up/4-5.PNG) # In[75]: import sys # In[76]: import sys for thing in sys.argv: print(thing, end='||||') # #### [추가 내용] copy() # - D.copy()는 Shallow Copy를 수행한다. # In[77]: phone = {'a': [1,2,3], 'b': 4} phone2 = phone.copy() print(phone) print(phone2) print() phone['b'] = 100 print(phone) print(phone2) print() phone['a'][0] = 100 print(phone) print(phone2) # # In[ ]: