Python_1 - jjin-choi/study_note GitHub Wiki

Β§ Intro

Β§ ν•¨μˆ˜μ™€ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°

1. 파이썬 ν•¨μˆ˜μ˜ νŠΉμ§•

  3 def add(x, y):
  4     return x+y
  5  
  6 a= add(3, 4)
  7 print (a)
  8 print (type(add))
  9 print (add)
  • output
    • line 7 ) 7
    • line 8 ) <class 'function'>
    • line 9 ) <function add at 0x7f682f067e18>
 11 import sys         
 12 sys.getrefcount(add) 
 13     
 14 add1 = add         
 15 a = add1(3, 4)     
 16     
 17 print(type(add1))  
 18 print (add1)       
 19 sys.getrefcount(add)  
  • add1 κ³Ό add 의 μ£Όμ†Œκ°’μ΄ κ°™λ‹€ ↔ 같은 객체λ₯Ό 가리킀고 있음
  • sys.getrefcount λŠ” 뭘까?
  • νŒŒμ΄μ¬μ—μ„œλŠ” ν•¨μˆ˜κ°€ 객체이닀. (symbol둜 가리킬 수 μžˆλŠ” λͺ¨λ“  type이 λͺ¨λ‘ 객체이닀.)
  • ν•¨μˆ˜λŠ” refcount = 0 μΌλ•Œ μ™„μ „νžˆ μ œκ±°λœλ‹€.

2. default parameter

  • μΈμžλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν–ˆμ„ λ•Œ μ •ν•΄μ§€μ§€λ§Œ, default parameterλŠ” ν•¨μˆ˜ μ •μ˜ μ‹œμ— 정해진닀.
  1 a = 10
  2  
  3 def foo(x=a):
  4     return x
  5  
  6 a = 5
  7 print (foo())  
  • default parameterλŠ” μ •μ˜ μ‹œ 정해지며, runtime μƒμ—μ„œλŠ” 사라지지 μ•ŠλŠ”λ‹€.
 10 def foo(x, items=[]):
 11     items.append(x)
 12     return items
 13  
 14 print(foo(1))
 15 print(foo(2))
 16 print(foo(3))
  • λ”°λΌμ„œ 처음 μ •μ˜μ‹œμ—λŠ” None 이라고 λ„£κ³ , None 일 λ•Œ μƒμ„±ν•˜λ„λ‘ μˆ˜μ •
 18 def foo(x, items=None):
 19     if items is None:
 20         items = []
 21     items.append(x)
 22     return items
 23  
 24 print(foo(1))   
 25 print(foo(2))
 26 print(foo(3))

3. κ°€λ³€ 인자

  • *κ°€ 뢙은건, python ν˜•νƒœμ˜ κ°€λ³€μΈμž (pointerκ°€ μ•„λ‹˜)

  • μΈμžμ— *을 μ‚¬μš©ν•˜λ©΄ 남아 μžˆλŠ” λͺ¨λ“  μΈμˆ˜κ°€ __νŠœν”Œ__λ‘œμ„œ packingλ˜μ–΄ args λ³€μˆ˜μ— μ €μž₯λœλ‹€.

  • νŠœν”Œμ€ 값을 λ°”κΏ€ 수 μ—†μŒ

  • ν‚€μ›Œλ“œ 인자 : foo(x=3, y=22, w='hello', z=[1,2]) 라고 넣어도 x, y, w, z κ°€ key 역할을 ν•˜μ—¬ μ‹€μ œ function foo μ—μ„œμ˜ key 값을 μ°Ύμ•„ 값을 λŒ€μž…ν•œλ‹€.

    • κΈ°λ³Έ μΈμžλž‘ ν‚€μ›Œλ“œ 인자λ₯Ό μ„žμ–΄μ„œ 넣을 수 있음
    • ν•˜μ§€λ§Œ κΈ°λ³Έ μΈμžλŠ” μˆœμ„œλŒ€λ‘œ λ“€μ–΄κ°€κΈ° λ•Œλ¬Έμ— 뒀에 남은 ν‚€μ›Œλ“œ μΈμžλŠ” μ•žμ—μ„œμ˜ κΈ°λ³Έ 인자λ₯Ό λ‹€μ‹œ 섀정해쀄 수 μ—†λ‹€.
  • **κ°€ λΆ™μœΌλ©΄, κ°€λ³€ ν‚€μ›Œλ“œ 인수라고 ν•œλ‹€.

  • κ°€λ³€ ν‚€μ›Œλ“œ μΈμžλŠ” __λ”•μ…”λ„ˆλ¦¬__λ‘œμ„œ μ €μž₯ν•œλ‹€.

    • %> parms.pop("fgcolor", "black") : fgcolor 의 defaultλŠ” black 이고 값이 λ“€μ–΄μ˜€λ©΄ κ·Έ κ°’μœΌλ‘œ.
  1 def make_table(data, **params):     
  2     fgcolor = params.pop("fgcolor", "black")
  3     bgcolor = params.pop("bgcolor", "white")
  4     width = params.pop("width", None)
  5  
  6     print (fgcolor)
  7     print (bgcolor)
  8     print (width)
  9  
 10     if params:
 11         raise TypeError (f"Unsupported configuration options {list(params)}")
 12  
 13 items = [1, 2, 3]
 14 make_table(items, fgcolor="red", bgcolor="black", border=1)

4. ν‚€μ›Œλ“œ λ§€κ°œλ³€μˆ˜λ§Œ λ°›λŠ” ν•¨μˆ˜

  1 def recv(maxsize, *, block=True):
  2     print (maxsize, block)
  3  
  4 recv(8192, block=False)     # Work
  5  
  6 try:
  7     recv(8192, False)       # Fail
  8 except TypeError as e:
  9     print (e)
 10  
 11  
 12 def minimum(*values, clip=None):
 13     m = min(values)
 14  
 15     if clip is not None:
 16         m = clip if clip > m else m
 17     return m
 18  
 19 print (minimum(1, 5, 2, -5, 10))
 20 print (minimum(1, 5, 2, -5, 10, clip=0)) 
  • python μ—μ„œλŠ” call by reference μ΄λ―€λ‘œ ν•¨μˆ˜ λ‚΄μ—μ„œ κ°’ λ³€κ²½ μ‹œ μ›λž˜ 객체 값에도 λ°˜μ˜λœλ‹€.
  • β€» m = clip if clip > m else m
  • β€» for I, x in enumerate(items)
  • μ—¬λŸ¬ 값을 return ν•˜λ©΄ νŠœν”Œμ— λ„£μ–΄μ„œ 1개의 κ°’μœΌλ‘œ return λœλ‹€.

5. 유효 λ²”μœ„ (scope)

  • μ „μ—­ λ³€μˆ˜ aκ°€ 있고 ν•¨μˆ˜ λ‚΄λΆ€a κ°€ μžˆμ„ λ•Œ ν•¨μˆ˜ λ‚΄λΆ€μ˜ aλŠ” ν•¨μˆ˜μ— μ†ν•œ 지역 λ³€μˆ˜
  • ν•¨μˆ˜ λ‚΄μ—μ„œ global a을 μ‚¬μš©ν•˜λ©΄, μ „μ—­ λ„€μž„μŠ€νŽ˜μ΄μŠ€ aλ₯Ό μ˜λ―Έν•œλ‹€.
  1 a = 42
  2 b = 37
  3  
  4 def foo():
  5     global a
  6     a = 13
  7     b = 0
  8  
  9 foo()
 10 print (f"a = {a}, b = {b}")
  • nested ν•¨μˆ˜ (쀑첩 ν•¨μˆ˜) μ•ˆμ˜ λ³€μˆ˜μ˜ 이름은 μ–΄νœ˜ 유효 λ²”μœ„μ— 따라 μ°Ύμ•„ 진닀.
    • 즉 쀑첩 ν•¨μˆ˜ λ‚΄μ—μ„œ λ³€μˆ˜κ°€ μ—†μœΌλ©΄ ν•œμΉΈ λ°–μœΌλ‘œ λ‚˜κ°€μ„œ λ³€μˆ˜ λ₯Ό μ°ΎλŠ”λ‹€.
    • ν•˜μ§€λ§Œ λ°”κΉ₯μͺ½ ν•¨μˆ˜μ—μ„œ μ •μ˜λœ 지역 λ³€μˆ˜ 값을 μ•ˆμͺ½ ν•¨μˆ˜μ—μ„œ λ‹€μ‹œ ν• λ‹Ήν•  μˆ˜λŠ” μ—†λ‹€.
    • unboundLocalError : local variable 'n' referenced before assignment
    • 그런데 ! λ°”κΉ₯μͺ½ ν•¨μˆ˜μ—μ„œ μ •μ˜λœ 지역 λ³€μˆ˜ 값을 μ•ˆμͺ½ ν•¨μˆ˜μ—μ„œ λ‹€μ‹œ ν• λ‹Ήν•˜λŠ” 방법이 μžˆλ‹€.
    • λ°”λ‘œ nonlocal 을 μ‚¬μš©ν•˜λ©΄ λœλ‹€.
    • nonlocal 은 자기 scope λ°–μ˜ κ°€μž₯ κ°€κΉŒμš΄ λ°”κΉ₯μͺ½ ν•¨μˆ˜μ—μ„œ μ •μ˜λœ 지역 λ³€μˆ˜λ₯Ό λ¬ΆλŠ”λ‹€.
 12 #---------------------------------------- 
 13 def countdown(start):
 14     n = start
 15     def display():
 16         print (f'T-minus {n}')
 17          
 18     while n > 0:
 19         display()
 20         n -= 1
 21          
 22 countdown(3)
 23 #---------------------------------------- 
 24          
 25 def countdown(start):
 26     n = start
 27     def display():
 28         print (f'T-minus {n}')
 29          
 30     def decrement():
 31         n -= 1
 32          
 33     while n > 0:
 34         display()
 35         decrement() # Error
 36          
 37 countdown(3)
 38 #---------------------------------------- 
 39 def countdown(start):
 40     n = start
 41     def display():
 42         print (f'T-minus {n}')
 43          
 44     def decrement():
 45         nonlocal n
 46         n -= 1
 47          
 48     while n > 0:
 49         display()
 50         decrement() # Error
 51          
 52 countdown(3)

6.lambda ν•¨μˆ˜

  • lambda λŠ” 1쀄 ν•¨μˆ˜μ΄λ‹€. λ‹€λ₯Έ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œλŠ” 읡λͺ… ν•¨μˆ˜λΌκ³ λ„ λΆ€λ₯Έλ‹€.
  • ν”„λ‘œκ·Έλž¨ λ‚΄μ—μ„œ ν•¨μˆ˜λ₯Ό μž¬μ‚¬μš© ν•˜μ§€ μ•ŠμœΌλ €λŠ” 경우 lambda ν•¨μˆ˜λ₯Ό μ“Έ 수 μžˆλ‹€.
  • 일반 ν•¨μˆ˜μ™€ ν˜•νƒœλ„ λΉ„μŠ·ν•˜κ³  λΉ„μŠ·ν•˜κ²Œ μž‘λ™.
    • format : lambda (인자) : (return)
  1 add = lambda x, y : x + y
  2 # μ•„λž˜ ν•¨μˆ˜μ™€ 동일 
  3 # def add(x, y):
  4 #    return x + y 
  • μ–Έμ œ μ“°λ©΄ νŽΈν• κΉŒ?
    • sorting ν•  λ•Œ μ‚¬μš©ν•˜λ©΄ νŽΈν•˜λ‹€.
  8 a = [(1, 2), (4, 1), (9, 10), (13, -3)]
  9 a.sort(key=lambda x: x[1])
 10 print (a)
 11 # sort by second value 
  • μ£Όμ˜μ‚¬ν•­
    • λžŒλ‹€μ—μ„œ μ‚¬μš©ν•œ x 값이 μ‹€ν–‰ μ‹œκ°„μ— λ‹¬λΌμ§€λŠ” λ³€μˆ˜μ΄λ‹€.
    • default parameterκ°€ μ•„λ‹ˆλΌ μ „μ—­ λ³€μˆ˜μΌ 뿐이닀.
    • ν•¨μˆ˜λ₯Ό μ •μ˜ν•  λ•Œ νŠΉμ • 값을 κ³ μ •ν•˜κ³  μ‹ΆμœΌλ©΄, λ””ν΄νŠΈ parameter둜 μ§€μ •ν•˜λ©΄ λœλ‹€.
 14 x = 10
 15 a = lambda y : x + y
 16 x = 20
 17 b = lambda y : x + y
 18  
 19 print ("\nlambda function1")
 20 print (a(10)) # output : 30
 21 print (b(10)) # output : 30
 22  
 23 #----------------------------------------
 24 x = 10
 25 a = lambda y, x=x : x + y
 26 x = 20
 27 b = lambda y, x=x : x + y
 28  
 29 print ("\nlambda function2")  
 30 print (a(10)) # output : 30
 31 print (b(10)) # output : 30
  • list comprehension

    • ex) func = [lambda x: x+n for n in range(5)]
    • β†’ func = [lambda x, n=n : x+n for n in range(5)]
    • n 값이 λ³€ν•  것이라고 κΈ°λŒ€ ν•˜μ§€λ§Œ λžŒλ‹€ ν•¨μˆ˜λŠ” κ°€μž₯ λ§ˆμ§€λ§‰ 값을 μ‚¬μš©ν•œλ‹€.
    • n 값을 ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜λŠ” μ‹œμ μ˜ κ°’μœΌλ‘œ 고정해놓고 μ‚¬μš©ν•œλ‹€.
  • ν•¨μˆ˜ μΈμžμ— meta data λ„£κΈ°

    • ex) def add(x:int, y:int) -> int:
    • help(add) ν˜Ήμ€ add.annotations μ΄μš©ν•΄μ„œ λ³Ό 수 있음
    • μΈμžμ— 정보λ₯Ό μΆ”κ°€ν•΄μ„œ λ‹€λ₯Έ μ‚¬λžŒμ΄ ν•¨μˆ˜λ₯Ό μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λŠ”μ§€ μ•Œ 수 μžˆλ„λ‘ ν•œλ‹€.
    • ν•¨μˆ˜μ˜ 주석은 ν•¨μˆ˜μ˜ __annotations__에 μ €μž₯λœλ‹€.

7.closure

  • closure
    • closure λž€?
    • ν•¨μˆ˜κ°€ λ°μ΄ν„°λ‘œ 취급될 λ•ŒλŠ” ν•¨μˆ˜κ°€ μ •μ˜λœ 곳의 μ£Όλ³€ ν™˜κ²½ 정보가 ν•¨κ»˜ μ €μž₯λœλ‹€.
    • ν•¨μˆ˜κ°€ return ν•  λ•Œ 자기 내뢀에 μžˆλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” 경우
    • ν•¨μˆ˜λ₯Ό κ΅¬μ„±ν•˜λŠ” λ¬Έμž₯κ³Ό μ‹€ν–‰ ν™˜κ²½μ„ ν•¨κ»˜ 묢은 것을 closure 라고 ν•œλ‹€.
    • 이 μ˜ˆμ‹œμ—μ„œλŠ” mul_add κ°€ closure, μšΈνƒ€λ¦¬ μ•ˆμ— μžˆλŠ” κ°’ μ΄λΌλŠ” 의미
    • ν•¨μˆ˜λ₯Ό ν•œ 번 ν˜ΈμΆœν•˜λ©΄ κ·Έ μ•ˆμ˜ closure κ°€ 계속 μœ μ§€λ˜λ©° λ‹€μ‹œ 호좜 μ‹œ 또 λ‹€λ₯Έ closure κ°€ μƒμ„±λœλ‹€.
    • closure 내뢀에 closure 에 free variable (지역 λ³€μˆ˜) 이 μ €μž₯λ˜μ–΄ μžˆλ‹€.
  1 def calc():
  2     a = 3
  3     b = 5
  4  
  5     def mul_add(x):
  6         return a * x + b
  7     return mul_add
  8  
  9 c = calc()
 10 print (c(1), c(2), c(3), c(4))
 11  
 12  
 13 print (c.__closure__)
 14 print (c.__closure__[0].cell_contents)
 15 print (c.__closure__[1].cell_contents)  
  • κ΅¬ν˜„μ΄ κ°„λ‹¨ν•œ μˆ˜μ‹μΈ 경우 λžŒλ‹€λ₯Ό μ΄μš©ν•˜μ—¬ ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. λ‚΄λΆ€ ν•¨μˆ˜λ₯Ό 직접 ν˜ΈμΆœν•  일이 μ—†μœΌλ―€λ‘œ 이름이 없어도 λœλ‹€.
 18 def calc():
 19     a = 3
 20     b = 5
 21      
 22     return lambda x: a * x + b 
 23      
 24 c = calc()
 25 print (c(1), c(2), c(3), c(4))
 26      
 27      
 28 print (c.__closure__)
 29 print (c.__closure__[0].cell_contents)
 30 print (c.__closure__[1].cell_contents)
 31      
  • ν΄λ‘œμ € λ‚΄λΆ€μ—μ„œ μ •μ˜ν•œ λ³€μˆ˜μ— 접근도 κ°€λŠ₯ν•˜λ‹€.
    1. nonlocal μ„ μ–ΈμœΌλ‘œ λ‚΄λΆ€ λ³€μˆ˜λ₯Ό μˆ˜μ •ν•˜λŠ” ν•¨μˆ˜λ₯Ό μž‘μ„±
    2. μ ‘κ·Ό λ©”μ†Œλ“œλ₯Ό ν΄λ‘œμ € ν•¨μˆ˜μ— λΆ™μ—¬ 마치 μΈμŠ€ν„΄μŠ€ λ©”μ†Œλ“œμΈ κ²ƒμ²˜λŸΌ λ™μž‘ν•˜λŠ” 것
    • n의 값은 closure에 λ“€μ–΄μžˆκ³ , property의 ν•¨μˆ˜λ“€μ€ dict ν˜•νƒœλ‘œ μ €μž₯λ˜μ–΄ μžˆλ‹€.
 33 def sample():
 34     n = 0
 35  
 36     def func():
 37         print ('n = ', n)
 38  
 39     def get_n():
 40         return n
 41  
 42     def set_n(value):
 43         nonlocal n
 44         n = value
 45  
 46     func.get_n = get_n
 47     func.set_n = set_n
 48     return func
 49  
 50  
 51 if __name__ == '__main__':
 52     f = sample()
 53     f()
 54  
 55     n = 0
 56     f.set_n(10)
 57  
 58     f()
 59     print(f.get_n()) 

8. decorator

  • 이 μ˜ˆμ‹œμ—μ„œλŠ” func 이 μ§€μ—­λ³€μˆ˜, 즉 closure의 ν™˜κ²½μ΄ λœλ‹€.
    • make_func_alarm μ—μ„œ func μ΄λΌλŠ” μΈμžκ°€ λ“€μ–΄μ˜€λŠ”λ°, 이 ν•¨μˆ˜ 호좜이 λλ‚˜λ©΄ func 은 μ‚¬λΌμ§€μ§€λ§Œ closure μ—λŠ” λ‚¨μ•„μžˆλ‹€.
    • λ”°λΌμ„œ ν•¨μˆ˜λ₯Ό 인자둜 λ°›μ•„μ„œ, ν•¨μˆ˜ 전후에 μƒˆλ‘œμš΄ κΈ°λŠ₯을 μΆ”κ°€ν•œ ν•¨μˆ˜λ₯Ό λ§Œλ“€ μˆ˜λ„ μžˆλ‹€. !
    • make_func_alarm 이 decorator κ°€ λœλ‹€.
  1 def big_number(n):                   
  2     return n ** n ** n
  3  
  4 def make_func_alarm(func):
  5  
  6     def new_func(*args, **kwargs):
  7         print (" function start ! ")
  8         result = func(*args, **kwargs)
  9         print (" function end ! ")
 10         return result
 11  
 12     return new_func
 13  
 14 new_func = make_func_alarm(big_number)
 15 new_func(6)
  • μ—¬κΈ°μ„œ line 14 와 line 15 κ°€ λ²ˆκ±°λ‘­λ‹€.
    • μ•ˆμ— μžˆλŠ” closureλ₯Ό λ°›μ•„μ„œ λ‹€μ‹œ ν•œλ²ˆ ν˜ΈμΆœν•΄μ€˜μ•Ό ν•˜λŠ” λ²ˆκ±°λ‘œμ›€μ΄ μžˆμ–΄, python μ—μ„œλŠ” 이λ₯Ό μžλ™μœΌλ‘œ ν•΄μ£ΌλŠ” macro κ°€ μžˆλ‹€.
  • @λ₯Ό μ‚¬μš©ν•˜μž !
    • @make_time_checker 문법은 decorator
    • make_time_checker λΌλŠ” ν•¨μˆ˜μ—λ‹€κ°€ big_numberλ₯Ό λ„˜κΈ΄ ν˜•νƒœ
    • 즉 μ–΄λ–€ ν•¨μˆ˜ μœ„μͺ½μ— @__ λ₯Ό μ¨μ€€λ‹€λŠ” 것은, κ·Έ ν•¨μˆ˜λ₯Ό decorator에 λ„˜κ²¨μ£Όκ² λ‹€λŠ” 의미.
    • μ‹€μ œλ‘œλŠ” μœ„ μ½”λ“œμ™€ λ™μΌν•œ 역할을 ν•΄μ€€λ‹€.
  1 import time       
  2                   
  3 def make_func_checker(func):
  4                   
  5     def new_func(*args, **kwargs):
  6         start_time  = time.perf_counter()
  7         result      = func(*args, **kwargs)
  8         end_time    = time.perf_counter() 
  9         print ("runtime : ", end_time - start_time)
 10         return result
 11     return new_func
 12                   
 13 @make_func_checker 
 14 def big_number(n):
 15     return n ** n ** n
 16 # big_number = make_time_checker(big_number)                  
 17 big_number(7) 
  • Tracer tool (μ–΄λ–€ ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€ λ‹€ 둜그둜 남기고 싢을 λ•Œ)
    • enable_tracing 을 True / False 둜 해두어, tracing 을 할지 말지λ₯Ό κ²°μ •ν•  수 μžˆλ‹€.
    • μ§€κΈˆμ€ μ‚¬μš©λ²• μ •λ„λ§Œ.. !
  1 enable_tracing = True
  2              
  3 if enable_tracing:
  4     debug_log = open("debug.log", "w")
  5              
  6 def trace(func):
  7     if enable_tracing:
  8         def callf(*args, **kwargs):
  9             debug_log.write("\n\n--------------------------------------------")
 10             debug_log.write(f"\nCalling {func.__name__} : {args} {kwargs}\n")
 11             r = func(*args, **kwargs)
 12             debug_log.write(f"{func.__name__} returned {r}\n")
 13             debug_log.write("--------------------------------------------\n\n")
 14              
 15             return r
 16         return callf
 17     else:    
 18         return func
 19              
 20 @trace       
 21 def square(x):
 22     return x * x
 23              
 24 square(100) 

9. Iterator

  • 반볡자 : μˆœν™˜ κ°€λŠ₯ν•œ μ•„μ΄ν…œμ— μ ‘κ·Όν•  λ•Œ for μˆœν™˜λ¬Έμ„ μ‚¬μš©ν•˜κ³  싢지 μ•Šλ‹€λ©΄ !? iterator μ‚¬μš©ν•˜λ©΄ λœλ‹€.
    • with : context manager (λ‚˜μ€‘μ— κ³΅λΆ€ν•˜κΈ°λ‘œ..)
    • nextλŠ” iterator λ₯Ό μ‚¬μš©ν•˜μ˜€μŒ.
    • 이 μ˜ˆμ œμ—μ„œλŠ” 더 이상 nextλ₯Ό ν•  수 없을 λ•Œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜κ²Œ 되고 이 λ•Œ StopIteration
  1 with open("debug.log") as f : # f = open("passwd")  
  2     try:
  3         while True:
  4             line = next(f)
  5             print(line)
  6     except StopIteration:
  7         pass
  • ν•¨μˆ˜ iter (iterator의 μ•½μž)
    • it λŠ” python μ—μ„œλŠ” reference (cμ—μ„œλŠ” pointer) κ°€ λœλ‹€.
    • iter은 list μ΄λ‚˜ file 이든 μ–΄λ–€ containerκ°€ μ˜€λ“ μ§€ sequential ν•˜λ©΄ 순차적으둜 μ΄λ™ν•˜λŠ” reference κ°€ 되며 이게 κ°€λŠ₯ν•œ containerλ₯Ό iterable container 라고 λΆ€λ₯΄λ©° μ‹€μ œλ‘œ μ΄λ™ν•˜λŠ” 이 referenceλ₯Ό iterator 라고 λΆ€λ₯Έλ‹€.
 10 items = [1, 2, 3]  # list 
 11 it = iter(items)   # print (it) : <list_iterator object at ...>
 12 print (next(it))
 13 print (next(it))
 14 print (next(it))

10. Delegating μˆœν™˜

  • [func] : special function
  • μ•„λž˜ μ˜ˆμ‹œμ—μ„œ root Node 의 _children list에 각각 child1 child2 λ₯Ό append ν•œλ‹€.
    • python μ—μ„œλŠ” tree λΌλŠ” ꡬ쑰체가 μ—†κΈ° λ•Œλ¬Έμ— 이λ₯Ό list 둜 가지고 λ§Œλ“€μ–΄ μ€€ 것
    • for ch in root μ΄λž€, μ•„λž˜ μ£Όμ„μ²˜λ¦¬λœ whileλ¬Έκ³Ό λ™μΌν•˜λ‹€
    • λ˜ν•œ print (객체) μ΄λ ‡κ²Œ ν•΄μ£Όλ©΄, 객체의 addressκ°€ λ‚˜μ˜€λ―€λ‘œ Node ν•¨μˆ˜ λ‚΄μ—λŠ” repr ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄, 값을 ν‘œμ‹œν•΄μ£ΌλŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄μ£Όμ—ˆλ‹€.
  1 class Node:
  2     def __init__(self, value):
  3         self._value = value
  4         self._children = []
  5          
  6     def __repr__(self):
  7         return f'Node({self._value})'
  8          
  9     def add_child(self, node):
 10         self._children.append(node)
 11          
 12     def __iter__(self):
 13         # iter(n1) == n1.__iter__()
 14         return iter(self._children) 
 15          
 16          
 17 if __name__ == '__main__':
 18     root = Node(0)
 19     child1 = Node(1)
 20     child2 = Node(2)
 21          
 22     root.add_child(child1)
 23     root.add_child(child2)
 24          
 25     for ch in root:
 26         print (ch)  # to print out _value, Node has __repr__ function
 27          
 28     # --- for loop ---
 29     # it = iter(root)
 30     # while True:
 31     #    ch = next(it)
 32     #    print (ch)

11. Generator

  • ν•¨μˆ˜ 객체의 yield (μ–‘λ³΄ν•˜λ‹€) λΌλŠ” μ˜ˆμ•½μ–΄κ°€ ν•˜λ‚˜λΌλ„ μžˆλ‹€λ©΄ generator 이닀.
    • x의 값을 λ˜μ Έμ£Όλ©΄μ„œ μ–‘λ³΄ν•œλ‹€..
    • yield λŠ” return κ³Ό κ°™μ§€λ§Œ ν•¨μˆ˜κ°€ λλ‚œ 것은 μ•„λ‹ˆλ‹€. ν•¨μˆ˜μ˜ μ œμ–΄κΆŒμ„ ν˜ΈμΆœμžμ—κ²Œ μ–‘λ³΄ν•œλ‹€.
    • yield κ°€ μžˆλŠ” ν•¨μˆ˜λŠ” 일반 ν•¨μˆ˜κ°€ μ•„λ‹ˆλΌ generator 이기 λ•Œλ¬Έμ— c = countdown(3) 이라고 ν•˜λ©΄ generator 객체λ₯Ό λ„˜κ²¨μ£ΌλŠ” 것.
    • next λ₯Ό ν•˜κ²Œ 되면 yield κ΅¬λ¬ΈκΉŒμ§€ μˆ˜ν–‰λ˜κ³ , 이 λ•Œ yield κ°’ n을 λ„˜κ²¨μ£Όλ©΄μ„œ λ©ˆμΆ˜λ‹€.
    • κ·Έ λ‹€μŒ next κ°€ μ˜¬λ•Œ κΉŒμ§€ yield 에 λ©ˆμΆ°μžˆλ‹€κ°€ nextκ°€ 또 λ“€μ–΄μ˜€λŠ” μˆœκ°„ yield λ‹€μŒ ν–‰λΆ€ν„° μˆ˜ν–‰λœλ‹€.
    • iterator 와 λ™μΌν•œ λ™μž‘μ„ ν•œλ‹€. (λ‹€λ₯Έ 점은, 이미 μžˆλŠ” container인 list 같은걸 μˆœνšŒν•˜λŠ”κ²Œ μ•„λ‹ˆλΌ κ·Έ λ•Œ κ·Έ λ•Œ μƒμ„±λ˜λŠ” 값을 가지고 μ œμ–΄ 쑰건을 ν•˜λ‚˜μ”© μ–‘λ³΄ν•˜λ©΄μ„œ ν•¨μˆ˜ λ°–κ³Ό μ•ˆμ„ ν•˜λ‚˜ν•˜λ‚˜μ”© μ²˜λ¦¬ν•˜λŠ” 병행 처리λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.
def countdown(n): 
    print('Starting to count from',n)
    while n > 0:
        yield n
        n -= 1
    print('Done!')

12. iterator & generator

  • python μ—μ„œ tree ꡬ쑰λ₯Ό μˆœνšŒν•˜λ €λ©΄ μž¬κ·€ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•˜λ‚˜ μ‹Άμ§€λ§Œ,
    • 맨 μ•„λž˜μ— for ch in root.depth_first(): μ—μ„œλŠ” generatorλ₯Ό κΊΌλ‚΄λŠ” 것이고 (μ™œλƒλ©΄ depth_first ν•¨μˆ˜μ— yield κ°€ μžˆμœΌλ―€λ‘œ)
    • depth_first μ•ˆμ—μ„œ for c in self: μ—μ„œλŠ” self 에 μžˆλŠ” list의 iterator κ°€ ν˜ΈμΆœλ˜λŠ” 것.
    • yield from [A] 은 [A] 에 μžˆλŠ” iterator 을 μ΄μš©ν•΄μ„œ λ‚˜μ—κ²Œ μ–‘λ³΄ν•˜λΌλŠ” 의미
    • root - left - right 둜 μˆœνšŒν•˜λŠ” pre order traverse μ•Œκ³ λ¦¬μ¦˜μ΄ λœλ‹€. (root λΆ€ν„° λ°©λ¬Έν•˜λŠ” 것)
  1 class Node:
  2     def __init__(self, value):
  3         self._value = value
  4         self._children = []
  5          
  6     def __repr__(self):
  7         return f' :: Node({self._value}) ::'
  8          
  9     def add_child(self, node):
 10         self._children.append(node)
 11          
 12     def __iter__(self):
 13         return iter(self._children)
 14          
 15     def depth_first(self):
 16         yield self    
 17         for c in self:
 18             yield from c.depth_first()
 19          
 20          
 21 if __name__ == '__main__':
 22     root = Node(0)
 23     child1 = Node(1)
 24     child2 = Node(2)
 25          
 26     root.add_child(child1)
 27     root.add_child(child2)
 28          
 29     child1.add_child(Node(3))
 30     child1.add_child(Node(4))
 31     child2.add_child(Node(5))
 32          
 33     for ch in root.depth_first():
 34         print (ch)
 35          
 36     # g = root.depth_first()
 37     # while True : 
 38     #    ch = next(g)
 39     #    print (ch, end = '')
 40     #    
 41     #    it = iter(self)
 42     #    while True: 
 43     #        ch = next(g)

13. reverse μˆœν™˜ 및 μƒνƒœλ₯Ό 가진 generator

  • deque λŠ” list와 λΉ„μŠ·ν•˜μ§€λ§Œ μ™Όμͺ½ 였λ₯Έμͺ½μ—μ„œ μ‚½μž… κ°€λŠ₯ (stack, queue λ‘œλ„ μ‚¬μš©κ°€λŠ₯)
  • 객체 μžμ²΄μ— for .. in .. 을 μ‚¬μš©ν•˜λ©΄ 객체 λ‚΄λΆ€μ˜ iter ν•¨μˆ˜λ₯Ό νƒ€κ²Œ λœλ‹€. (μ—†μœΌλ©΄ κΈ°λ³Έ iter ν•¨μˆ˜ λ™μž‘)
  • generator μƒνƒœλŠ” ν˜„μž¬ line 수, max λ₯Ό 가지고 있게 λœλ‹€.
 30 from collections import deque
 31                  
 32 class linehistory:
 33     def __init__(self, lines, histlen=3):
 34         self.lines = lines
 35         self.history = deque(maxlen=histlen)
 36                  
 37     def __iter__(self):
 38         for lineno, line in enumerate(self.lines, 1):
 39             self.history.append((lineno, line))
 40             yield line
 41                  
 42     def clear(self):
 43         self.history.clear()
 44                  
 45 with open('debug.log') as f:
 46     lines = linehistory(f)
 47                  
 48     for line in lines:
 49         if 'python' in line:
 50             for lineno, hline in lines.history:
 51                 print (f'{lineno} : {hline}') 

14. iterator & generator

  • list 인 경우 slice κ°€λŠ₯ν•˜μ§€λ§Œ generator λŠ” [:] κ°€ λ˜μ§€ μ•ŠμŒ (TypeError : 'generator' object is not subscriptable)
    • 이λ₯Ό μ§€μ›ν•˜λŠ”κ²Œ itertools !
  1 import itertools
  2      
  3 for x in itertools.islice(c, 10, 20):
  4     print (x) 
  • μˆœν™˜ 객체 첫 번째 λΆ€λΆ„ κ±΄λ„ˆλ›°κΈ°
  1 from itertools import dropwhile
  2 with open("debug.log") as f:
  3     for line in dropwhile(lambda line: line.startswith('#'), f):
  4         print (line)
  • enumerate(list) μ‚¬μš©ν•˜λ©΄ (index, value) λ₯Ό return ν•΄μ€Œ

    • enumerate(list, 1) 이라고 ν•˜λ©΄ 1λΆ€ν„° index μ‹œμž‘
  • zip (x, y) 라고 ν•˜λ©΄ x 와 y의 λ˜‘κ°™μ€ indexλ₯Ό λ™μ‹œ μˆœν™˜

    • x와 y의 κ°œμˆ˜κ°€ λ§žμ§€ μ•ŠλŠ” κ²½μš°μ—λŠ” 항상 짧은 μͺ½μœΌλ‘œ μˆœνšŒν•œλ‹€.
    • λ§Œμ•½ κΈ΄ μͺ½μœΌλ‘œ μˆœνšŒν•˜κΈ°λ₯Ό μ›ν•œλ‹€λ©΄, zip_longest λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.
  6 a = [1, 2, 3]
  7 b = ['w', 'x', 'y', 'z']
  8      
  9 from itertools import zip_longest
 10 for i in zip(a, b):
 11     print (i)
 12      
 13 for i in zip_longest(a, b):
 14     print (i)     

15. coroutine

  • generator 쀑 ν•˜λ‚˜
  • generator μ—μ„œ yieldλŠ” μ™Όμͺ½μ— 아무것도 μ—†μ–΄μ„œ, ν•¨μˆ˜κ°€ 이 지점에 λ„μ°©ν•˜λ©΄ n μ΄λΌλŠ” 것을 λ°˜λŒ€μͺ½μ— μ–‘λ³΄ν•˜κ³  μ œμ–΄κΆŒμ΄ λ©ˆμΆ”μ—ˆλŠ”λ°, μ½”λ£¨ν‹΄μ—μ„œλŠ” μ¦‰μ‹œ μ œμ–΄κΆŒμ„ 양보 yield의 λ°©ν–₯이 R value둜 κ°€μžˆμŒ.
    • μœ„μ—μ„œμ˜ yield λŠ” dataλ₯Ό λ„˜κ²¨μ£ΌλŠ” κ΅¬μ‘°μ˜€λ‹€λ©΄, μ§€κΈˆμ˜ yield λŠ” dataλ₯Ό λ°›μ•„μ£ΌλŠ” ꡬ쑰.
    • 끝내기 μœ„ν•΄μ„œλŠ” close λΌλŠ” ν•¨μˆ˜κ°€ 있음
  1 def receiver():
  2     print ("Ready to receive")
  3  
  4     while True:
  5         n = yield
  6         print (f"Got {n}")
  7  
  8 r = receiver()
  9 print (r)
 10  
 11 next(r) 
 12 r.send(1)
 13 r.send(2)
 14 r.send("Hello")
  • coroutine κ³Ό decorator (nextλ₯Ό μžλ™μœΌλ‘œ ν•΄ μ£ΌλŠ” μ—­ν• ) λ₯Ό 같이 써주면 μ’‹λ‹€.
    • close 이후에도 send λ₯Ό ν•˜λ©΄ generator κ°€ 이미 stop 쑰건을 λ§Œλ‚œ 뒀이기 λ•Œλ¬Έμ— StopIteration μ—λŸ¬ λ°œμƒν•œλ‹€.
 16 def coroutine(func):
 17     def start (*args, **kwargs):
 18         g = func(*args, **kwargs)
 19         next (g)
 20         return g
 21     return start
 22      
 23 @coroutine
 24 def receiver():
 25     print ("\nReady to receive")        
 26     while True:
 27         n = yield
 28         print (f"Got {n}")
 29      
 30 receiver()
 31 r.send("coroutine with decorator")
 32 r.close()
  • generator 와 coroutine 을 ν•¨κ»˜ μ“°λ©΄ pipe 역할을 ν•˜κ²Œ λœλ‹€.
    • ps -ef | grep ls | wc -l 이런 pipe !
    • code λŠ” reference μ—μ„œ μ°Έκ³ ν•˜κΈ° (1.16)