Python DecoratorπŸ’… - 1


learn_python_mac_thumb800.webp

μ΅œκ·Όμ— μ˜ˆμ „μ— μ§  νšŒμ‚¬ μ½”λ“œλ₯Ό μ •λ¦¬ν•˜λ©΄μ„œ μ€‘λ³΅λ˜λŠ” μ½”λ“œλ₯Ό λ°μ½”λ ˆμ΄ν„°λ‘œ 정리해 λ³΄μ•˜μŠ΅λ‹ˆλ‹€.
λ‚˜μ˜μ§€ μ•Šμ€ 방법인듯 ν•˜μ—¬ λ°μ½”λ ˆμ΄ν„°λ₯Ό 주제둜 글을 μ“°κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹Ή
괜히 μ“°λ©΄ μžˆμ–΄λ³΄μ΄λŠ”(μ €λŠ” κ·Έλž¬μŠ΅λ‹ˆλ‹€πŸ€ͺ) λ°μ½”λ ˆμ΄ν„°λ₯Ό μ•Œμ•„λ³΄μ•„μš”

λ§Œμ•½ 제 글이 μ•ˆ μ½νžˆκ±°λ‚˜ λΆ€μ‘±ν•˜κ±°λ‚˜ λ³„λ‘œμž„! μ•„λ¬΄νŠΌ λ³„λ‘œμž„! 이라면 μ•„λž˜ 쒋은 κΈ€λ“€λ‘œ 눈 μ •ν™”λ₯Ό λΆ€νƒλ“œλ¦½λ‹ˆλ‹€ 😭
<μ œκ°€ Decoratorλ₯Ό 곡뢀할 λ•Œ μ°Έκ³ ν–ˆμ—ˆλ˜ κΈ€ λͺ©λ‘μž…λ‹ˆλ‹€! 읽고 이해 λ˜μ…¨λ‹€λ©΄ 이 κΈ€λ‘œ λ‹€μ‹œ λŒμ•„μ˜€μ§€ μ•ŠμœΌμ…”λ„ λ©λ‹ˆλ‹€ :)>

λ°μ½”λ ˆμ΄ν„°λŠ” ν•„μš”μ— 따라 λ‹€μ–‘ν•˜κ²Œ μž‘μ„±ν•˜κ³  ν™œμš©ν•  수 μžˆμ–΄μ„œ μ•„λž˜ 주제둜 λ‚˜λˆ„μ–΄ λ‹€λ€„λ³΄κ³ μž ν•©λ‹ˆλ‹€

  1. λ°μ½”λ ˆμ΄ν„°λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•œ 사전 지식과, ν•¨μˆ˜λ‘œ λ§Œλ“  λ°μ½”λ ˆμ΄ν„°μ™€ κ·Έ μ‚¬μš© 방법
  2. 클래슀둜 λ§Œλ“  λ°μ½”λ ˆμ΄ν„°, 인자λ₯Ό 받을 수 μžˆλŠ” λ°μ½”λ ˆμ΄ν„°, μ€‘μ²©λœ λ°μ½”λ ˆμ΄ν„°μ˜ μ‹€ν–‰ μˆœμ„œ

μ΄λ²ˆμ—λŠ” λ°μ½”λ ˆμ΄ν„°λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•œ 사전 지식과, ν•¨μˆ˜λ‘œ λ§Œλ“  λ°μ½”λ ˆμ΄ν„°μ™€ κ·Έ μ‚¬μš© 방법 에 λŒ€ν•΄ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€

Prerequisite


λ°μ½”λ ˆμ΄ν„°λΌλŠ” 주제λ₯Ό λ„˜μ–΄κ°€λŠ” κ°œλ…μ— λŒ€ν•œ μ„€λͺ…은 μ–΄λŠμ •λ„λŠ” μƒλž΅ν•˜λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€
근데, 이런 κ°œλ…λ“€μ„ λͺ°λΌλ„ κ·Έλƒ₯ 써보고 고치고 ν•˜λ©΄μ„œ λ°°μš°λŠ”κ±° μ•„λ‹κΉŒμš”β€¦?
(μ €λŠ” λ©μ²­ν•΄μ„œ μž‘λ…„λΆ€ν„° μ—΄μ‹¬νžˆ μ‚½μ§ˆν•˜κ³  μ˜¬ν•΄κ°€ λ˜μ–΄μ„œμ•Ό μ–΄λŠ 정도 μ΄ν•΄ν–ˆμŠ΅λ‹ˆλ‹€!)

μ•Œκ³  κ³„μ‹œλ©΄ 이해에 λ”μš± λ„μ›€λ˜λŠ” 것듀

Decorator κΈ°λ³Έ κ°œλ…


ν—€λ“œ 퍼슀트 λ””μžμΈ νŒ¨ν„΄ μ±…μ˜ Decorator Pattern 예제둜
카페의 음료 κΈ°λ³Έ λ‹¨μœ„μΈ μ—μŠ€ν”„λ ˆμ†Œμ™€, 우유, 물에 첨가물을 λŠ˜λ €κ°€λ©°
μƒˆλ‘œμš΄ 객체(라떼, μΉ΄ν‘ΈμΉ˜λ…Έ 카라멜 λ§ˆν‚€μ•„λ˜ λ“±)λ₯Ό μƒμ„±ν•΄λ‚΄λŠ”(μ±…μž„μ„ ν™•μž₯ν•˜λŠ”) λΉ„μœ κ°€ μžˆμŠ΅λ‹ˆλ‹€.

λ°μ½”λ ˆμ΄ν„°λ₯Ό μ΄μš©ν•΄, λ°˜λ³΅μ„ 쀄이고 λ©”μ†Œλ“œλ‚˜ ν•¨μˆ˜μ˜ μ±…μž„μ„ ν™•μž₯ν•œλ‹€λŠ” λ©΄μ—μ„œλŠ” μ–΄λŠμ •λ„ λΉ„μŠ·ν•˜λ‹€κ³  생각이 λ“­λ‹ˆλ‹€.
(μžλ°”μ˜ Annotation κ³Ό μƒκΉ€μƒˆλŠ” μœ μ‚¬ν•˜μ§€λ§Œ ν•˜λŠ” 일은 λ‹€λ¦…λ‹ˆλ‹Ή)

μ•„λ¬΄νŠΌ μš”μ•½ν•˜μžλ©΄
파이썬의 λ°μ½”λ ˆμ΄ν„°λ₯Ό ν•œ λ‹¨μ–΄λ‘œ μ •λ¦¬ν•˜μžλ©΄, ν΄λ‘œμ € μž…λ‹ˆλ‹€
μ’€ 더 ν’€μ–΄μ„œ 이야기 ν•˜λ©΄, ν΄λ‘œμ €μ˜ 좕약문법 μž…λ‹ˆλ‹€.

Closure


λ°μ½”λ ˆμ΄ν„°μ˜ λ³Έμ§ˆμ€ ν΄λ‘œμ €μž…λ‹ˆλ‹€. 이미 μ•Œκ³  κ³„μ‹œλ‹€λ©΄ κ³Όκ°ν•˜κ²Œ 더 이상 읽지 μ•ŠμœΌμ…”λ„ λ©λ‹ˆλ‹€!
ν΄λ‘œμ €κ°€ 뭐냐 ν•˜λ©΄ ν•¨μˆ˜μ— ν•¨μˆ˜μΈκ±°μž„γ…‹γ…‹γ…‹μ—Œγ…‹γ…‹γ…‹γ…‹
μ£„μ†‘ν•©λ‹ˆλ‹€β€¦ μ•„λž˜ μ½”λ“œλ₯Ό λ³΄μ‹œμ Έ

# ν•˜μŠ€μŠ€ν†€μ˜ μ•ˆλ…•λ‘œλ΄‡
def annoy_o_tron(message):
    # μ•ˆλ…•λ‘œλ΄‡μ΄ 인사할 수 μžˆλ„λ‘ ν•΄μ£ΌλŠ” λ‚΄λΆ€ κ΅¬ν˜„
    def greeting(name):
      print(f'{message} - {name}!')
      return greeting

    # annoy_o_tron ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’μ€ def greeting(name): print(...) μž…λ‹ˆλ‹€
    # print(f'Hello - {name}') ν•¨μˆ˜λ₯Ό κ°’μ²˜λŸΌ 가지고 μžˆλŠ” μƒνƒœλΌκ³  ν•  수 μžˆκ² λ„€μš”
    hello_o_tron = annoy_o_tron('Hello')

    # print('Hello - Doondoony!') ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€
    hello_o_tron('Doondoony') # Hello - Doondoony!
    hello_o_tron('velog') # Hello - velog!

annoy_o_tron ν•¨μˆ˜λŠ” message λ₯Ό 인자둜 받은 λ’€
λ‹€μŒμ— 이름을 받을 수 μžˆλŠ” ν•¨μˆ˜μΈ greeting ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

근데 greeting ν•¨μˆ˜μ˜ print(f'{message} - {name}!') λ¬Έμ—μ„œ
message λ³€μˆ˜λŠ” greeting μ•ˆμ— μ—†λŠ”λ° μ–΄λ–»κ²Œ 'Hello'λ₯Ό 좜λ ₯ν•  수 μžˆμ„κΉŒμš”?

그건 greeting ν•¨μˆ˜κ°€ μ„ μ–Έλ˜λŠ” μ‹œμ μ— message λΌλŠ” λ³€μˆ˜λ₯Ό μ°Ύμ„λ•Œ
LEGB μˆœμ„œ (Local, Enclosing, Global, Built-in) 에 따라 νƒμƒ‰ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€!
(μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” { } κ°€ 각각의 μŠ€μ½”ν”„λ₯Ό κ°–μ§€λ§Œ, νŒŒμ΄μ¬μ—μ„œλŠ” LEGB만 λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό κ°€μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€)

μœ„ μ½”λ“œμ—μ„œ defκ°€ λͺ‡ 번 μ€‘μ²©λ˜μ–΄ μžˆλ”λΌλ„ κ³„μ†ν•΄μ„œ λΆ€λͺ¨μ˜ λΆ€λͺ¨μ˜ λΆ€λͺ¨μ˜β€¦ ν•¨μˆ˜κ°€ κ°€μ§€λŠ” scope(enclosing)λ₯Ό 탐색할 수 있기 λ•Œλ¬Έμ—
message λ³€μˆ˜κ°€ LEGBμ•ˆμ— μ‘΄μž¬ν•œλ‹€λ©΄ μ°Ύμ•„ λƒ…λ‹ˆλ‹€ (μ½”λ“œ 내에 message λ³€μˆ˜κ°€ μ—†μœΌλ©΄ μ—λŸ¬κ°€ λ°œμƒν•˜κ² μ£ !)

이처럼 **message의 값을 κΈ°μ–΅ν•˜κ³  ν˜ΈμΆœν•  λ•Œ 항상 같은 message κ°’μœΌλ‘œ μ‹€ν–‰λ˜λŠ” ν™˜κ²½μ„ κΈ°μ–΅ν•˜λŠ” ν•¨μˆ˜λ₯Ό
ν΄λ‘œμ €λΌκ³  ν•  수 μžˆμŠ΅λ‹ˆλ‹Ή

λ°μ½”λ ˆμ΄ν„°μ˜ μ’…λ₯˜ - λˆ„κ°€ λ°μ½”λ ˆμ΄ν„°κ°€ 될 수 μžˆλ‚˜μš”?


λ³Έμ§ˆμ μœΌλ‘œλŠ” callableν•œ κ°μ²΄λŠ” λ°μ½”λ ˆμ΄ν„°λ‘œμ¨ μ‚¬μš© κ°€λŠ₯ν•©λ‹ˆλ‹€
λ‹€λ§Œ 각각의 μ„ΈλΆ€ κ΅¬ν˜„μ€ λ‹€λ¦…λ‹ˆλ‹Ή
(ν•¨μˆ˜λΌλ©΄ ν΄λ‘œμ € ν˜•νƒœλ‘œ μ§œμ—¬ μžˆμ–΄μ•Ό ν•˜κ² μ£ !)

callable ν•œ 객체라고 ν•˜λ©΄ λ§‰λ§‰ν•˜λ‹ˆκΉŒ 쑰금 μ •λ¦¬ν•΄λ³΄μžλ©΄

  1. ν•¨μˆ˜ λ°μ½”λ ˆμ΄ν„°
  2. 클래슀 λ°μ½”λ ˆμ΄ν„°

그리고 1번 2번 λͺ¨λ‘ 미리 μ •μ˜λœ 인자λ₯Ό 받을 수 μžˆλŠ” λ°μ½”λ ˆμ΄ν„°κ°€ 될 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€! (이건 λ‹€μŒλ²ˆμ—)

λ°μ½”λ ˆμ΄ν„°μ˜ μ’…λ₯˜ - μ˜ˆμ‹œ


ν•¨μˆ˜κ°€ 싀행될 λ•Œ λ§ˆλ‹€ κ·Έ κ²°κ³Όλ₯Ό 좜λ ₯ν•΄μ£ΌλŠ” loggerλΌλŠ” λ°μ½”λ ˆμ΄ν„°λ₯Ό μž‘μ„±ν•œλ‹€κ³  κ°€μ •ν•˜κ² μŠ΅λ‹ˆλ‹€
아직 이해가 λ˜μ§€ μ•ŠμœΌμ‹ λ‹€λ©΄, κ·Έλƒ₯ λ°μ½”λ ˆμ΄ν„° 역할을 ν•  ν•¨μˆ˜λŠ” λŒ€μΆ© μ΄λ ‡κ²Œ μƒκ²Όκ² κ΅¬λ‚˜ ν•˜μ‹œλ©΄ λ˜κ² μŠ΅λ‹ˆλ‹€ 😘

  • ν•¨μˆ˜λ₯Ό λ°μ½”λ ˆμ΄ν„°λ‘œ μ‚¬μš©ν•  경우

    def logger(func):
        def wrapper(*args, **kwargs):
          result = func(*args, **kwargs)
          print(f'Result: {result}')
          return result
        return wrapper
    
    @logger
    def add(a, b):
        return a + b
    
    result = add(20, 22) # Result: 42
    print(result) # 42
    
  • 클래슀λ₯Ό λ°μ½”λ ˆμ΄ν„°λ‘œ μ‚¬μš©ν•  경우

    class Logger(object):
        def __init__(self, func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            result = self.func(*args, **kwargs)
            print(f'Result: {result}')
            return result
    
    @Logger
    def add(a, b):
        return a + b
    
    result = add(20, 22) # Result: 42
    print(result) # 42
    
  • λžŒλ‹€ ν‘œν˜„μ‹ ν™œμš©ν•΄ λ°μ½”λ ˆμ΄ν„°λ‘œ μ‚¬μš©ν•  경우
    λžŒλ‹€ ν‘œν˜„μ‹μ€ κ°’μœΌλ‘œ 평가 되기 λ•Œλ¬Έμ—, print문을 μ‚¬μš©ν•œλ‹€λ©΄, λ°˜ν™˜ λ˜λŠ” 값을 μ§€μ •ν•˜κΈ°κ°€ 쑰금 지저뢄해 μ§‘λ‹ˆλ‹€

    logger = lambda fn: lambda *args, **kwargs: print(f'Result: {fn(*args, **kwargs)}')
    
    @logger
    def add(a, b):
        return a + b
    
    result = add(20, 22) # Result: 42
    print(result) # None...
    

    ꡳ이 값을 λ°˜ν™˜ν•˜κ³  μ‹ΆμœΌμ‹œλ‹€λ©΄... μ•„λž˜μ™€ 같이 ν•  수 μžˆμ„κ±° κ°™μ•„μš” (더 쒋은 방법이 μžˆλ‹€λ©΄ μ•Œλ €μ£Όμ„Έμš”!)

    logger = lambda fn: lambda *args, **kwargs: (print(f'Result: {fn(*args, **kwargs)}'), fn(*args, **kwargs))[1] # ν•¨μˆ˜ μ‹€ν–‰ 결과만 λ°˜ν™˜, printλŠ” κ·ΈλŒ€λ‘œ μ‹€ν–‰
    
    @logger
    def add(a, b):
        return a + b
    
    result = add(20, 22) # Result: 42
    print(result) # 42
    

λ°μ½”λ ˆμ΄ν„° 문법


μœ„μ˜ μ˜ˆμ œμ—μ„œλ„ μ•Œ 수 μžˆμ§€λ§Œ ν•¨μˆ˜ λ˜λŠ” 클래슀, λ©”μ„œλ“œ λ“± callableν•œ 객체의 μ„ μ–ΈλΆ€ 상단에
@둜 μ‹œμž‘ν•˜λŠ” ν•¨μˆ˜λͺ…을 μ μ–΄μ£ΌλŠ” ν˜•νƒœλ₯Ό 띄어야 ν•©λ‹ˆλ‹€!
(Pycharm μ—μ„œ λ°μ½”λ ˆμ΄ν„° 뒀에 ν•¨μˆ˜λ‚˜ λ‹€λ₯Έ λ°μ½”λ ˆμ΄ν„°κ°€ μ˜€μ§€ μ•Šμ„ 경우 Syntax Error: @ or def expected μ—λŸ¬λ₯Ό ν‘œμ‹œν•©λ‹ˆλ‹€)

@timer # ν•¨μˆ˜μ˜ μ •μ˜λΆ€ 상단에 μ μš©ν•  λ°μ½”λ ˆμ΄ν„°λ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€
def foo():
    pass

@timer # 클래슀 μ •μ˜λΆ€ 상단에 μ μš©ν•  λ°μ½”λ ˆμ΄ν„°λ₯Ό μž‘μ„±ν•΄λ„ λ©λ‹ˆλ‹€
class Bar(object):
    pass

class Baz(object):
    @timer # 클래슀의 λ©”μ„œλ“œ λ‹Ήμ—°ν•˜κ²Œλ„ λ©λ‹ˆλ‹€
    def qux(self):
      pass

@timer
doondoon = 'Doondoony' # [X] 이런건 μ•ˆλ©λ‹ˆλ‹€...

# callable ν•œ κ°μ²΄μ—λŠ” λͺ¨λ‘ μ‚¬μš© κ°€λŠ₯ν•©λ‹ˆλ‹€
callable(foo) # True
callable(Bar) # True
callable(Baz().qux) # True
callable(doondoon) # False

λ°μ½”λ ˆμ΄ν„°λŠ” ν΄λ‘œμ €μ˜ 좕약문법?


λ°μ½”λ ˆμ΄ν„°λŠ” ν΄λ‘œμ €μ˜ μΆ•μ•½ 문법이라고 ν–ˆλŠ”λ° μ‹€μ œλ‘œ μ–΄λ–»κ²Œ μΆ•μ•½ λ˜λŠ”μ§€ μ•Œμ•„μ•Όκ² μ Έ
PEP-318 에 μžˆλŠ” 예제λ₯Ό (거의)κ·ΈλŒ€λ‘œ μΈμš©ν•˜κ² μŠ΅λ‹ˆλ‹€!
synchronized, classmethod λŠ” callableν•œ 객체둜 μ–΄λ–€ 일을 μˆ˜ν–‰ν•˜λŠ” ν•¨μˆ˜ μ •λ„λ‘œλ§Œ 생각 ν•΄μ£Όμ„Έμš”!

def synchronized(lock):
    # codes below...
    pass

def classmethod(arg):
    # codes below...
    pass

def foo(cls):
    # codes below...
    pass

foo = synchronized(lock)(foo)
foo = classmethod(foo)

# μœ„μ˜ μ½”λ“œμ™€ μ™„μ „νžˆ λ™μΌν•©λ‹ˆλ‹€
# κ·Έλ ‡λ‹€λ©΄ μ‹€ν–‰μˆœμ„œλŠ” λ°μ½”λ ˆμ΄ν„°κ°€ μŒ“μ—¬μžˆλŠ” μ•„λž˜μ—μ„œ μœ„λ‘œ μ‹€ν–‰λ˜λŠ”κ±Έ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹Ή
@classmethod
@synchronized(lock)
def foo(cls):
    pass

μ΄λ ‡κ²Œ λ³΄λ‹ˆκΉŒ 별 κ±° μ•„λ‹ˆμ£ ?

λ°μ½”λ ˆμ΄ν„°μ˜ μ‹€ν–‰ μˆœμ„œ


κ°€μž₯ μ€‘μš”ν•œ 건 ν•¨μˆ˜ μœ„μ— @decorator λ₯Ό μ μš©ν•  λ•Œ greeting ν•¨μˆ˜κ°€ decorator ν•¨μˆ˜ μ•ˆμœΌλ‘œ λ“€μ–΄κ°„λ‹€λŠ” μ μž…λ‹ˆλ‹€
μ€‘μ²©λœ λ°μ½”λ ˆμ΄ν„°λŠ” λ°”λ‘œ μœ„μ—μ„œ μ„€λͺ…λ“œλ Έλ‹€μ‹œν”Ό μ•„λž˜μ—μ„œ μœ„λ‘œ μ‹€ν–‰λ©λ‹ˆλ‹€.

μ €λŠ” λ°μ½”λ ˆμ΄ν„°κ°€ μ•„λž˜ ν•¨μˆ˜λ₯Ό 감싼닀고 이미지화 ν•˜κ³  μžˆμ–΄μš”

def decorator(func):
    print('in decorator function') #1
    # 2번과 3번의 μ‹€ν–‰ μˆœμ„œλŠ” λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— λ‹¬λ €μžˆμŠ΅λ‹ˆλ‹€ (λ°μ½”λ ˆμ΄ν„°μ™€λŠ” μˆœμ„œ 무관)
    def wrapper(*args, **kwargs):
      print('in wrapper function') #2
      func(*args, **kwargs) #3

      return wrapper


@decorator
def greeting():
    print('in greeting')


if __name__ == '__main__':
    greeting()

κ·Έλž˜μ„œ λ°μ½”λ ˆμ΄ν„°λ₯Ό μ–Έμ œ μ–΄λ–»κ²Œ μ“°λŠ”λ’ˆ


μ–Έμ œ, μ–΄λ–»κ²Œ 써야 μ’‹μ€μ§€λŠ” λ‹Ήμ—°ν•œ μ΄μ•ΌκΈ°μ§€λ§Œ λ‹¨μ •μ μœΌλ‘œ μ–˜κΈ°ν•˜κΈ° μ–΄λ ΅μŠ΅λ‹ˆλ‹€ πŸ˜…
λ‹€λ§Œ, κ°œμΈμ μœΌλ‘œλŠ” μœ„μ— μž‘μ„±ν•œ 것 처럼
λ°μ½”λ ˆμ΄ν„°λ₯Ό μ΄μš©ν•΄, λ°˜λ³΅μ„ 쀄이고 λ©”μ†Œλ“œλ‚˜ ν•¨μˆ˜μ˜ μ±…μž„μ„ ν™•μž₯ν•œλ‹€λŠ” 역할에 κ±Έλ§žλ„λ‘ μ‚¬μš©ν•˜λ €κ³  λ…Έλ ₯ μ€‘μž…λ‹ˆλ‹€.
(μ•„λž˜ μž₯, λ‹¨μ μ—μ„œλ„ 이야기 ν•˜κ² μ§€λ§Œ λ¬΄λΆ„λ³„ν•œ λ°μ½”λ ˆμ΄ν„° μ‚¬μš©μ€ μ½”λ“œ 가독성을 λ–¨μ–΄λœ¨λ¦½λ‹ˆλ‹€)

μ•„λž˜ μ½”λ“œλ“€μ€ κ·ΈλŸ¬ν•œ 역할에 맞게 μž‘μ„±ν•œ λͺ‡ 가지 μ˜ˆμ œμž…λ‹ˆλ‹€.
μ‹€ν–‰ κ°€λŠ₯ν•œ μ½”λ“œλŠ” Gist에도 올렀 λ‘μ—ˆμŠ΅λ‹ˆλ‹Ή!

μ‹€ν–‰λ˜λŠ” ν•¨μˆ˜μ˜ μ‹€ν–‰ μ‹œκ°„μ„ μΈ‘μ •ν•˜κΈ° μœ„ν•œ 타이머 κΈ°λŠ₯

  • λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ 😭
  • μ•„λž˜ μ½”λ“œμ™€ 같이 계속 μ‹œμž‘ μ‹œμ μ— μ‹œκ°„μ„ λ§Œλ“€κ³ , ν”„λ¦°νŠΈ ν•¨μˆ˜λ₯Ό μž…λ ₯ν•΄μ•Ό ν•©λ‹ˆλ‹€ (λ¬Όλ‘  이 λ˜ν•œ 잘 λ¬Άμ–΄μ„œ 좔상화 ν•  수 μžˆμ§€λ§Œ...)
  import functools
  import time


  # μ‹œμž‘, μ’…λ£Œ μ‹œκ°„μ„ μ²΄ν¬ν•΄μ„œ ν”„λ¦°νŠΈ ν•˜λŠ” μ½”λ“œλ₯Ό ν•¨μˆ˜μ•ˆμ— λ°˜μ˜ν•©λ‹ˆλ‹€.
  def huge_add(a, b):
      start = time.time()
      result = a + b
      time.sleep(1)
      print(f'add Elapsed time: {round((time.time() - start), 4)} seconds')
      return result


  # huge_add 와 같은 일을 ν•˜λŠ” μ½”λ“œκ°€ λ°˜λ³΅λ©λ‹ˆλ‹Ή
  def huge_subtract(a, b):
      start = time.time()
      result = a + b
      time.sleep(1)
      print(f'subtract Elapsed time: {round((time.time() - start), 4)} seconds')
      return result


  # 같은 일을 ν•˜λŠ” μ½”λ“œκ°€ λ°˜λ³΅λ©λ‹ˆλ‹Ή
  def huge_multiply(a, b):
      start = time.time()
      result = a * b
      time.sleep(1)
      print(f'multiply Elapsed time: {round((time.time() - start), 4)} seconds')
      return result


  if __name__ == '__main__':
      huge_number = 10e8
      huge_add(huge_number, huge_number)
      huge_subtract(huge_number, huge_number)
      huge_multiply(huge_number, huge_number)

  # 좜λ ₯
  # add Elapsed time: 1.0039 seconds
  # subtract Elapsed time: 1.0048 seconds
  # multiply Elapsed time: 1.0048 seconds
  • λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•œλ‹€λ©΄ 😎
  • μ•„λž˜μ™€ 같이 timer ν•¨μˆ˜μ˜ μ •μ˜ ν•œλ²ˆμœΌλ‘œ @timerλ₯Ό μ μš©ν•˜κΈ°λ§Œ ν•˜λ©΄, λ°”λ‘œ μ‹€ν–‰ μ‹œκ°„μ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€!
import functools
import time


def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f'{func.__name__} took {round((time.time() - start), 4)} seconds')
        return result

    return wrapper


# timer λ°μ½”λ ˆμ΄ν„° 적용
@timer
def huge_add(a, b):
    result = a + b
    time.sleep(1)
    return result


@timer
def huge_subtract(a, b):
    result = a + b
    time.sleep(1)
    return result


@timer
def huge_multiply(a, b):
    result = a * b
    time.sleep(1)
    return result


if __name__ == '__main__':
    huge_number = 10e8
    huge_add(huge_number, huge_number)
    huge_subtract(huge_number, huge_number)
    huge_multiply(huge_number, huge_number)


# 좜λ ₯, μ΄μ œλŠ” κ°„νŽΈν•˜κ²Œ 호좜된 ν•¨μˆ˜ 이름도 확인할 수 μžˆμŠ΅λ‹ˆλ‹€
# huge_add took 1.0037 seconds
# huge_subtract took 1.0044 seconds
# huge_multiply took 1.0028 seconds

http request의 status code μœ νš¨μ„± 검증

  • 정상적인 μš”μ²­μ΄ μˆ˜ν–‰λ˜μ—ˆλŠ”μ§€ validation을 맀번 ν•˜κΈ° λ³΄λ‹€λŠ” μ•„λž˜μ™€ 같이 μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€
from urllib.parse import urljoin

import urllib3
from urllib3.exceptions import HTTPError


def response_ok(func):
    def validate(*args, **kwargs):
        result = func(*args, **kwargs)
        if result.status != 200:
            raise HTTPError(f'Request Failed with status code {result.status}')
            return result

        return validate


@response_ok
def fetch(path):
    with urllib3.PoolManager() as http:
        return http.request('GET', path)


if __name__ == '__main__':
    api = 'http://httpbin.org'
    url = urljoin(api, 'ip')  # μ‘΄μž¬ν•˜λŠ” URL μž…λ‹ˆλ‹€. 200 응닡을 κΈ°λŒ€ν•©λ‹ˆλ‹€
    wrong_url = urljoin(api, 'pi')  # μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” URL μž…λ‹ˆλ‹€. 404 응닡을 κΈ°λŒ€ν•©λ‹ˆλ‹€
    fetch(url).data.decode()  
    fetch(wrong_url).data.decode()  # urllib3.exceptions.HTTPError: Request Failed with status code 404


# 좜λ ₯
# μ˜¬λ°”λ₯Έ URL둜 접속 μ‹œλ„μ‹œ
# '{\n  "origin": "1.2.3.4"\n}\n'

# 잘λͺ»λœ URL둜 접속 μ‹œλ„μ‹œ
# urllib3.exceptions.HTTPError: Request Failed with status code 404

μœ„μ˜ 예제λ₯Ό λ³΄λ‹ˆ μ‘°κΈˆμ€ μ‚¬μš©ν•΄μ•Όκ² λ‹€λŠ” 생각이 λ“œμ‹œλ‚˜μš”?
λ°μ½”λ ˆμ΄ν„°λŠ” 사싀 μ€‘λ³΅λ˜λŠ” μ½”λ“œμ˜ ν•˜λ‚˜μ˜ 좔상화 방법이라고 μƒκ°ν•©λ‹ˆλ‹€.
그리고 μΆ”μƒν™”λŠ” μ–Έμ œλ‚˜ λ‹€λ₯Έ λΉ„μš©μ„ μˆ˜λ°˜ν•©λ‹ˆλ‹€

λ°μ½”λ ˆμ΄ν„° μ‚¬μš©μ˜ μž₯, 단점


μž₯점

  1. 쀑볡을 μ œκ±°ν•˜κ³ , μ½”λ“œκ°€ 간결해진닀
  2. ν΄λ‘œμ €λ₯Ό 직접 μž‘μ„±ν•˜λŠ”κ²ƒ 보닀 λ¬Έλ²•μ μœΌλ‘œ κ°„κ²°ν•˜λ‹€
  3. λΆ€μˆ˜ 효과 μ—†λŠ” ν•¨μˆ˜λ‘œ μž‘μ„±λœ λ°μ½”λ ˆμ΄ν„°μ˜ 경우, μ‘°ν•©ν•΄μ„œ μ‚¬μš©ν•˜κΈ° μš©μ΄ν•˜λ‹€

단점

  1. λ‹Ήμ—°ν•˜μ§€λ§Œ, 이해도에 따라 μ½”λ“œ 가독성이 λ–¨μ–΄μ§ˆ 수 μžˆλ‹€
  2. νŠΉμ • λ©”μ„œλ“œ / ν•¨μˆ˜ ν•œμ •μ μΈ λ°μ½”λ ˆμ΄ν„°λŠ” 재 μ‚¬μš©μ„±μ΄ 떨어진닀
    • 그런 κ²½μš°μ—λŠ” κ·Έλƒ₯ ν•¨μˆ˜ 내뢀에 둜직으둜 λ°˜μ˜ν•˜λŠ”κ²Œ 더 λ‚˜μ€λ“― ν•©λ‹ˆλ‹€
  3. 디버깅이 μ–΄λ ΅λ‹€
    • λ°μ½”λ ˆμ΄ν„°κ°€ μ€‘μ²©λœ 경우, μ—λŸ¬κ°€ λ°œμƒν•œ 지점을 μΆ”μ ν•˜κΈ° 쑰금 κ³€λž€ν•œ κ²½μš°κ°€ μžˆμŠ΅λ‹ˆλ‹€
    • λ°μ½”λ ˆμ΄ν„° ν•¨μˆ˜μ—μ„œ ν•¨μˆ˜ 이름을 funcλ‚˜ fn λ“±μœΌλ‘œ λ°›μ•„μ„œ μ‹€ν–‰ν•˜κΈ° λ•Œλ¬Έμ—, μ–΄λ–€ ν•¨μˆ˜κ°€ μ—λŸ¬μΈμ§€ λͺ¨ν˜Έν•¨

끝


κΈ΄ κΈ€ μ½μ–΄μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€!🐢

μ–Έμ œλ‚˜ 잘λͺ»λœ λΆ€λΆ„μ΄λ‚˜ μ‹€ν–‰ μ•ˆλ˜λŠ” μ½”λ“œλŠ” 지적해 μ£Όμ‹œλ©΄ κ°μ‚¬ν•˜κ² μŠ΅λ‹ˆλ‹€
μ€‘μš”ν•œ μ—¬λŸ¬ κ°œλ…μ„ λ‹€λ£¨λŠ” λ‚΄μš©μ΄λ‹€λ³΄λ‹ˆ, κ°œλ…μ΄λ‚˜ 잘λͺ»λœ μ •μ˜κ°€ μžˆλ‹€λ©΄ κΌ­ μ•Œλ €μ£Όμ„Έμš”! λ°”λ‘œ μˆ˜μ •ν•˜κ² μŠ΅λ‹ˆλ‹€.

개인적인 μƒκ°μœΌλ‘œλŠ” Best Practiceλ₯Ό μ°Ύμ•„ κ·ΈλŒ€λ‘œ ν•˜λ €λŠ” μƒκ°λ•Œλ¬Έμ—
저도 λŒ€λΆ€λΆ„μ˜ κ°œλ…λ“€μ΄ 101 μˆ˜μ€€μ— 머물러 μžˆμ—ˆλŠ”λ°
κ·Έλƒ₯ 그런 생각없이 일단 μ μš©ν•˜κ³  천천히 μˆ˜μ •ν•΄ λ‚˜κ°€λ©΄μ„œ 많이 이해도가 λ†’μ•„μ‘Œλ˜κ²ƒ κ°™μŠ΅λ‹ˆλ‹€

μ’‹μ•„λ³΄μΈλ‹€λŠ” 이유둜 였,λ‚¨μš©ν•˜λŠ”κ²ƒλ„ 문제일 수 μž‡μ§€λ§Œ κ·ΈλŸ¬λ©΄μ„œ 많이 λ°°μ›Œλ‚˜κ°ˆ 수 μžˆλ‹€κ³  μƒκ°ν•˜λ‹ˆ
읡힌 κ°œλ…μ„ 마ꡬ마ꡬ μ μš©ν•΄λ³΄λ©΄ 쒋을 λ“― ν•΄μš”!

λ‹€μŒμ—λŠ” 클래슀 λ°μ½”λ ˆμ΄ν„°μ™€, 인자λ₯Ό 받을 수 μžˆλŠ” λ°μ½”λ ˆμ΄ν„°, μ€‘μ²©λœ λ°μ½”λ ˆμ΄ν„°μ˜ μ‚¬μš© 등에 λŒ€ν•΄ μ μ–΄λ³΄κ² μŠ΅λ‹ˆλ‹Ή 😘