μ½”λ“œ - 패캠 μˆ˜μ—… μ½”λ“œ μ°Έκ³  (패캠 μˆ˜μ—… 정리)

 

<이전 κΈ€>

https://silvercoding.tistory.com/25

 

이번 ν¬μŠ€νŠΈμ—μ„œλŠ” λ°μ½”λ ˆμ΄ν„°λ₯Ό μ•Œμ•„λ³Ό 것이닀. λ°μ½”λ ˆμ΄ν„°λŠ” μ–΄λ ΅λ‹€κ³  λŠλΌλŠ” 것이 λ‹Ήμ—°ν•˜λ‹€. λ°μ½”λ ˆμ΄ν„°μ— λ“€μ–΄κ°€κΈ° μ „μ—λŠ” λ³€μˆ˜μ˜ λ²”μœ„μ™€ ν΄λ‘œμ € κ°œλ…μ„ μ•Œμ•„μ•Ό ν•˜λ―€λ‘œ 이 λ‘˜μ„ λ¨Όμ € μ‚΄νŽ΄λ³΄μž.

 

- 파이썬 λ³€μˆ˜ λ²”μœ„ 

*** μ „μ—­λ³€μˆ˜ vs μ§€μ—­λ³€μˆ˜ μ°Έκ³  

https://wikidocs.net/62

 

μœ„ν‚€λ…μŠ€

온라인 책을 μ œμž‘ κ³΅μœ ν•˜λŠ” ν”Œλž«νΌ μ„œλΉ„μŠ€

wikidocs.net

μ—¬κΈ° μ΄ν•΄ν•˜κΈ° μ‰½κ²Œ 정리가 λ˜μ–΄μžˆλ‹€! 

 

직접 μ‹€μŠ΅ν•΄λ³΄μž 

# 예제 1
def func_v1(a):
    print(a)
    print(b)


# 였λ₯˜
# func_v1(5)

 Traceback (most recent call last): 
  File "c:/Users/./Desktop/python_high/chapter04_02.py", line 19, in <module>
    func_v1(5) 
  File "c:/Users/./Desktop/python_high/chapter04_02.py", line 15, in func_v1       
    print(b) 
 NameError: name 'b' is not defined 

 

예제1κ³Ό 같은 ν•¨μˆ˜λ₯Ό μž‘μ„±ν•˜κ³ , ν˜ΈμΆœν•˜λ©΄ λ‹Ήμ—°ν•œ 결과둜 NameErrorκ°€ λ‚œλ‹€. bκ°€ μ •μ˜λ˜μ–΄ μžˆμ§€ μ•Šμ€λ° bλ₯Ό 좜λ ₯ν•˜λΌκ³  μž‘μ„±ν•˜μ˜€κΈ° λ•Œλ¬Έμ΄λ‹€. 

 

 

# 예제 2 
b = 10

def func_v2(a):
    print(a)
    print(b)

func_v2(5)

κ·Έλ ‡λ‹€λ©΄ μ΄λ ‡κ²Œ ν•¨μˆ˜ 밖에 bλ₯Ό μ„ μ–Έν•˜κ³  ν•¨μˆ˜ μ•ˆμ—μ„œ bλ₯Ό 좜λ ₯ν•˜λ©΄ μ–΄λ–»κ²Œ 될까? 

 5  
 10  

μœ„μ™€ 같이 좜λ ₯이 λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€. μ΄λ•Œμ˜ bλ₯Ό μ „μ—­λ³€μˆ˜λΌκ³  ν•œλ‹€.

 

 

# 예제3 
b = 10

def func_v3(a):
    print(a)
    print(b)
    b = 5
    
func_v3(5)

μ΄λ ‡κ²Œ μž‘μ„±ν•œλ‹€λ©΄ μ–΄λ–»κ²Œ 될까? 

Traceback (most recent call last):
  File "c:/Users/sooki/Desktop/python_high/chapter04_02.py", line 42, in <module>      
    func_v3(5) 
  File "c:/Users/./Desktop/python_high/chapter04_02.py", line 39, in func_v3       
    print(b) 
UnboundLocalError: local variable 'b' referenced before assignment

였! UnboundLocalError κ°€ λ‚œλ‹€. ν• λ‹Ήλ˜κΈ° 전에 μ§€μ—­λ³€μˆ˜ 'b'κ°€ μ°Έμ‘°λ˜μ—ˆλ‹€λŠ” 것이닀. 

 

ν•¨μˆ˜ 내에 bκ°€ μžˆλŠ” 건 체크가 λ˜μ—ˆλŠ”λ°, b에 값을 ν• λ‹Ήν•˜κΈ° 전에 bλ₯Ό 좜λ ₯ν–ˆκΈ° λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ‚œλ‹€. 

같은 μ΄λ¦„μ˜ μ „μ—­λ³€μˆ˜μ™€ μ§€μ—­λ³€μˆ˜κ°€ 있으면 ν•¨μˆ˜ λ‚΄μ—μ„œλŠ” μ§€μ—­λ³€μˆ˜κ°€ μš°μ„ μ΄λ©°, λŸ°νƒ€μž„μ˜ 인터프리터가 bκ°€ μžˆλŠ” 것을 μ²΄ν¬ν–ˆμ§€λ§Œ, 할당은 μœ„μ—μ„œλΆ€ν„° μ•„λž˜λ‘œ 이루어지기 λ•Œλ¬Έμ΄λ‹€.

 

* 증λͺ…

from dis import dis

print('EX1-1 - ')
print(dis(func_v3))

EX1-1 -
 38           0 LOAD_GLOBAL              0 (print) 
              2 LOAD_FAST                0 (a) 
              4 CALL_FUNCTION            1 
              6 POP_TOP 

 39           8 LOAD_GLOBAL              0 (print) 
             10 LOAD_FAST                1 (b) 
             12 CALL_FUNCTION            1 
             14 POP_TOP 
 
 40          16 LOAD_CONST               1 (5) 
             18 STORE_FAST               1 (b)  
             20 LOAD_CONST               0 (None) 
             22 RETURN_VALUE 
 None 

 

 

 

- Closure (ν΄λ‘œμ €) 

1. λ°˜ν™˜λ˜λŠ” λ‚΄λΆ€ ν•¨μˆ˜μ— λŒ€ν•΄μ„œ μ„ μ–Έλœ μ—°κ²° 정보λ₯Ό 가지고 μ°Έμ‘°ν•˜λŠ” 방식 

2. λ°˜ν™˜ λ‹Ήμ‹œ ν•¨μˆ˜μ˜ μœ νš¨λ²”μœ„λ₯Ό λ²—μ–΄λ‚œ λ³€μˆ˜ λ˜λŠ” λ©”μ†Œλ“œμ— 직접 접근이 κ°€λŠ₯ 

 

κΈ€λ‘œ 읽으면 이해가 μ–΄λ €μš°λ‹ˆ 직접 μ‹€μŠ΅ν•΄λ³΄κΈ° . 

a = 10 

print('EX2-1 - ', a + 10)
print('EX2-2 - ', a + 100)
print('EX2-3 - ', sum(range(1, 51)))
print('EX2-4 - ', sum(range(51, 101)))

 EX2-1 -  20 
 EX2-2 -  110 
 EX2-3 -  1275 
 EX2-4 -  3775 

aλΌλŠ” λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜κ³  , λ”°λ‘œ λ”°λ‘œ 10, 100을 λ”ν•˜κ³  좜λ ₯ν•˜λ©΄ λ‹Ήμ—°ν•œ 결과둜 20, 110이 λ‚˜μ˜¨λ‹€. 

μœ„μ˜ μ˜ˆμ œλ“€ 처럼 κ°œλ³„μ μΈ 계산이 μ΄λ£¨μ–΄μ§€κ²Œ λœλ‹€. 

 

이와 λ‹€λ₯΄κ²Œ κ²°κ³Όλ₯Ό λˆ„μ ν•  μˆ˜λŠ” μ—†μ„κΉŒ? 에 λŒ€ν•œ λ‹΅μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλŠ” 것이 ν΄λ‘œμ €μ΄λ‹€. 

 

 

 

Q) κ²°κ³Όλ₯Ό λˆ„μ ν•  μˆ˜λŠ” μ—†μ„κΉŒ ? 

A1) 클래슀 이용 

class Averager():
    def __init__(self):
        self._series = []

    def __call__(self, v):
        self._series.append(v)
        print('class >>> {} / {}'.format(self._series, len(self._series)))
        return sum(self._series) / len(self._series)

μš°μ„  Averager ν΄λž˜μŠ€λŠ” 숫자λ₯Ό λ„£μœΌλ©΄ λ¦¬μŠ€νŠΈμ— μΆ”κ°€ν•˜μ—¬ 평균을 κ΅¬ν•΄μ£ΌλŠ” ν΄λž˜μŠ€μ΄λ‹€. 

객체λ₯Ό μƒμ„±ν•˜λ©΄ _series 에 빈 리슀트λ₯Ό μƒμ„±ν•œλ‹€. 

μ €λ²ˆ κΈ€μ—μ„œ 배운 __call__ λ©”μ†Œλ“œλŠ” 객체λ₯Ό λ©”μ†Œλ“œ ν˜•νƒœλ‘œ ν˜ΈμΆœν•  수 μžˆλ„λ‘ ν•΄ μ£ΌλŠ” κ²ƒμ΄μ—ˆλ‹€. 

 

# μΈμŠ€ν„΄μŠ€ 생성 
avg_cls = Averager()

print('EX3-1 - ', avg_cls(15))
print('EX3-2 - ', avg_cls(35))
print('EX3-2 - ', avg_cls(40))

 class >>> [15] / 1 
 EX3-1 -  15.0 
 class >>> [15, 35] / 2 
 EX3-2 -  25.0 
 class >>> [15, 35, 40] / 3 
 EX3-2 -  30.0 

μ΄λ ‡κ²Œ λˆ„μ μœΌλ‘œ μ €μž₯ν•΄λ‘μ—ˆλ‹€κ°€ 평균을 ꡬ해쀀닀. 

 

 

 

A2) ν΄λ‘œμ € 이용 

μ΄λ²ˆμ—” ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•œλ‹€. ν΄λ‘œμ €λ₯Ό μ‚¬μš©ν•˜λ©΄ 

1. μ „μ—­λ³€μˆ˜ μ‚¬μš© κ°μ†Œ 

2. λ””μžμΈ νŒ¨ν„΄ 적용 

def closure_avg1():
    # Free Variable
    # ν΄λ‘œμ € μ˜μ—­
    series = []
    def averager(v):
        # 여기에 seriesκ°€ μ—†λŠ”λ° 계속 μ°Έμ‘°ν•˜κ³  있음 
        # series = [] 여기에 μ“΄λ‹€λ©΄ 계속 μ΄ˆκΈ°ν™”λœ ν›„ append됨 
        series.append(v)
        print('def1 >>> {} / {}'.format(series, len(series)))
        return sum(series) / len(series)
    return averager # ν•¨μˆ˜ 자체λ₯Ό 리턴 averager() 이게 μ•„λ‹˜

 

ν΄λ‘œμ € μ˜μ—­μ—μ„œ seriesλ₯Ό μ„ μ–Έν•œ 것 λΉΌκ³ λŠ” λ‹€λ₯Έ 게 없어보인닀. μ›λž˜ ν•¨μˆ˜μ•ˆμ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜λŠ” ν•¨μˆ˜ 리턴과 λ™μ‹œμ— μ΄ˆκΈ°ν™”λœλ‹€. ν•˜μ§€λ§Œ ν΄λ‘œμ € μ˜μ—­μ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜λŠ” μ΄ˆκΈ°ν™” λ˜μ§€ μ•Šμ•„ μ΄λŸ¬ν•œ λˆ„μ μœΌλ‘œ μΆ”κ°€λ˜λŠ” μ½”λ“œλ₯Ό 지 λ•Œ μ‚¬μš©ν•  수 μžˆλ‹€. 

avg_closuer1 = closure_avg1()

print('EX4-1 - ', avg_closuer1(15))
print('EX4-1 - ', avg_closuer1(35))
print('EX4-1 - ', avg_closuer1(40))

μ§€κΈˆλ³΄λ‹ˆ μ˜€νƒ€κ°€ 났닀 closuer 이라고 λ˜μ–΄μžˆλ‹€! 

def1 >>> [15] / 1
EX4-1 -  15.0
def1 >>> [15, 35] / 2
EX4-1 -  25.0
def1 >>> [15, 35, 40] / 3
EX4-1 -  30.0

κ²°κ³Όκ°€ 잘 λ‚˜μ˜€λŠ” 것을 λ³Ό 수 μžˆλ‹€. 

print('EX5-1 - ', dir(avg_closuer1))
print()
print('EX5-2 - ', dir(avg_closuer1.__code__))
print()
print('EX5-3- ', avg_closuer1.__code__.co_freevars)  # ν΄λ‘œμ €μ— μ ‘κ·Ό
print()
print('EX5-4 - ', dir(avg_closuer1.__closure__[0]))  
print()
print('EX5-5 - ', dir(avg_closuer1.__closure__[0].cell_contents[1]))

EX5-1 -  ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

__code__ 에 μ ‘κ·Ό
EX5-2 -  ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
co_vars 에 μ ‘κ·Ό ---> ν΄λ‘œμ €μ— μ ‘κ·Ό 
EX5-3-  ('series',)
seriesκ°€ λ‚˜μ˜€λŠ” 것을 λ³Ό 수 μžˆλ‹€.
EX5-4 -  ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']

EX5-5 -  ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', 
'__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

 

 

 

*** 잘λͺ»λœ ν΄λ‘œμ € μ‚¬μš© 예 

def closure_avg2():
    # Free variable
    # ν΄λ‘œμ € μ˜μ—­ 
    cnt = 0 
    total = 0 
    
    def averager(v):
        cnt += 1
        total += v 
        print('def2 >>> {} / {}'.format(total, cnt))
        return total / cnt 
    return averager

 Traceback (most recent call last): 
  File "c:/Users/./Desktop/python_high/chapter04_02.py", line 155, in <module>     
    print('EX5-5 - ', avg_closure2(15)) 
  File "c:/Users/./Desktop/python_high/chapter04_02.py", line 147, in averager     
    cnt += 1 
 UnboundLocalError: local variable 'cnt' referenced before assignment 

μ΄λ ‡κ²Œ μ‚¬μš©ν•˜λŠ” κ²½μš°μ—λŠ” UnboundLocalErrorκ°€ μ‹€ν–‰λœλ‹€. 

 

 

 

---> 해결방법 

def closure_avg2():
    # Free variable
    # ν΄λ‘œμ € μ˜μ—­ 
    cnt = 0 
    total = 0 
    def averager(v):
        nonlocal cnt, total  
        cnt += 1
        total += v 
        print('def2 >>> {} / {}'.format(total, cnt))
        return total / cnt 
    return averager

<nonlocal λ³€μˆ˜λͺ…> 을 λΆ™μ—¬μ£Όλ©΄ ν΄λ‘œμ € μ˜μ—­μ„ μ‚¬μš©ν•˜μ—¬ λ³€μˆ˜λ₯Ό 선언해쀄 수 μžˆλ‹€. 

avg_closure2 = closure_avg2()

print('EX5-5 - ', avg_closure2(15))
print('EX5-5 - ', avg_closure2(35))
print('EX5-5 - ', avg_closure2(40))

 def2 >>> 15 / 1 
 EX5-5 -  15.0 
 def2 >>> 50 / 2 
 EX5-5 -  25.0 
 def2 >>> 90 / 3 
 EX5-5 -  30.0 

그럼 κ²°κ³Ό 값이 잘 λ‚˜μ˜€λŠ” 것을 λ³Ό 수 μžˆλ‹€. 

 

 

- λ°μ½”λ ˆμ΄ν„° , Decorator 

μž₯점

1. μ€‘λ³΅μ œκ±°, μ½”λ“œ κ°„κ²° 

2. ν΄λ‘œμ €λ³΄λ‹€ 문법 κ°„κ²° 

3. μ‘°ν•©ν•΄μ„œ μ‚¬μš©ν•  λ•Œ 용이 

 

단점 

1. 디버깅이 어렀움 

2. μ—λŸ¬μ˜ λͺ¨ν˜Έν•¨ 

 

import time 

def perf_clock(func): 
    def perf_clocked(*args):
        # μ‹œμž‘ μ‹œκ°„ 
        st = time.perf_counter()
        result = func(*args)
        # μ’…λ£Œ μ‹œκ°„ 
        et = time.perf_counter() - st
        # ν•¨μˆ˜λͺ… 
        name = func.__name__ 
        # λ§€κ°œλ³€μˆ˜ 
        arg_str = ','.join(repr(arg) for arg in args)
        # 좜λ ₯ 
        print('Result : [%0.5fs] %s(%s) -> %r' % (et, name, arg_str, result))
        return result
    return perf_clocked

μš°μ„  perf_clock μ΄λΌλŠ” ν•¨μˆ˜λ₯Ό μƒμ„±ν•œλ‹€. ν•¨μˆ˜λ₯Ό μž…λ ₯ν•˜λ©΄ κ·Έ ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜λŠ” 데 κ±Έλ¦¬λŠ” μ‹œκ°„κ³Ό κ·Έ ν•¨μˆ˜μ˜ λ°˜ν™˜ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•΄ μ£ΌλŠ” ν•¨μˆ˜μ΄λ‹€. 

 

 

* λ°μ½”λ ˆμ΄ν„° λ―Έμ‚¬μš© 

def time_func(seconds):
    time.sleep(seconds)


def sum_func(*numbers):
    return sum(numbers)


def fact_func(n):
    return 1 if n < 2 else n * fact_func(n-1)

총 3κ°€μ§€μ˜ ν•¨μˆ˜λ‘œ μ‹€ν—˜μ„ ν•΄λ³Έλ‹€. time_func : 2초 sleep , sum_fun : 숫자 ν•©ν•˜κΈ°, fact_func : νŒ©ν† λ¦¬μ–Ό 계산 

non_deco1 = perf_clock(time_func)
non_deco2 = perf_clock(sum_func)
non_deco3 = perf_clock(fact_func)

print('EX7-1 - ', non_deco1, non_deco1.__code__.co_freevars)
print('EX7-2 - ', non_deco2, non_deco2.__code__.co_freevars)
print('EX7-3 - ', non_deco3, non_deco3.__code__.co_freevars)

print('*' * 40, 'Called Non Deco -> time_func')
print('EX7-4 - ')
non_deco1(2)
print('EX7-5 - ')
non_deco2(100, 200, 300, 500)
print('EX7-6 - ')
non_deco3(100)

EX7-1 -  <function perf_clock.<locals>.perf_clocked at 0x0000029029B70EA0> ('func',)   
EX7-2 -  <function perf_clock.<locals>.perf_clocked at 0x0000029029B70F28> ('func',)   
EX7-3 -  <function perf_clock.<locals>.perf_clocked at 0x0000029029B74048> ('func',)   
**************************************** Called Non Deco -> time_func

 EX7-4 - Result : [2.00830s] time_func(2) -> None 
 EX7-5 -  Result : [0.00001s] sum_func(100,200,300,500) -> 1100 
 EX7-6 - Result : [0.00017s] fact_func(100) ->   93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 

perf_clock의 인자둜 각 ν•¨μˆ˜λ₯Ό λ„£μ–΄ λ³€μˆ˜λ₯Ό μ„ μ–Έν•΄μ€€λ‹€. κ·Έ λ‹€μŒ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ , μ›ν•˜λ˜ κ²°κ³Όκ°€ 잘 λ‚˜μ˜¨λ‹€! 

 

 

 

 

* λ°μ½”λ ˆμ΄ν„° μ‚¬μš© 

@perf_clock
def time_func(seconds):
    time.sleep(seconds)


@perf_clock
def sum_func(*numbers):
    return sum(numbers)


@perf_clock
def fact_func(n):
    return 1 if n < 2 else n * fact_func(n-1)

λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄ ν•¨μˆ˜ μœ„μ— @perf_clock 을 μž‘μ„±ν•œλ‹€. 

print('*' * 40, 'Called Deco -> time_func')
print('EX7-7 - ')
time_func(2)

print('*' * 40, 'Called Deco -> sum_func')
print('EX7-7 - ')
sum_func(10, 20, 30, 40, 50)

print('*' * 40, 'Called Deco -> fact_func')
print('EX7-7 - ')
fact_func(5)

**************************************** Called Deco -> time_func 
EX7-7 -
Result : [2.01093s] time_func(2) -> None 
**************************************** Called Deco -> sum_func 
EX7-7 -
Result : [0.00002s] sum_func(10,20,30,40,50) -> 150 
**************************************** Called Deco -> fact_func 
EX7-7 -
Result : [0.00000s] fact_func(1) -> 1 
Result : [0.00026s] fact_func(2) -> 2 
Result : [0.00058s] fact_func(3) -> 6 
Result : [0.00087s] fact_func(4) -> 24 
Result : [0.00110s] fact_func(5) -> 120 

그럼 μ΄λ ‡κ²Œ λ³€μˆ˜λ₯Ό 생성해주지 μ•Šμ•„λ„ κ°„λ‹¨ν•˜κ²Œ κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+ Recent posts