#!/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[ ]: