μ΅κ·Όμ μμ μ μ§ νμ¬ μ½λλ₯Ό μ 리νλ©΄μ μ€λ³΅λλ μ½λλ₯Ό λ°μ½λ μ΄ν°λ‘ μ λ¦¬ν΄ λ³΄μμ΅λλ€.
λμμ§ μμ λ°©λ²μΈλ― νμ¬ λ°μ½λ μ΄ν°λ₯Ό μ£Όμ λ‘ κΈμ μ°κ² λμμ΅λλΉ
κ΄ν μ°λ©΄ μμ΄λ³΄μ΄λ(μ λ κ·Έλ¬μ΅λλ€π€ͺ) λ°μ½λ μ΄ν°λ₯Ό μμ보μμ
λ§μ½ μ κΈμ΄ μ μ½νκ±°λ λΆμ‘±νκ±°λ λ³λ‘μ! μλ¬΄νΌ λ³λ‘μ! μ΄λΌλ©΄ μλ μ’μ κΈλ€λ‘ λ μ νλ₯Ό λΆνλ립λλ€ π
<μ κ° Decoratorλ₯Ό 곡λΆν λ μ°Έκ³ νμλ κΈ λͺ©λ‘μ
λλ€! μ½κ³ μ΄ν΄ λμ
¨λ€λ©΄ μ΄ κΈλ‘ λ€μ λμμ€μ§ μμΌμ
λ λ©λλ€ :)>
λ°μ½λ μ΄ν°λ νμμ λ°λΌ λ€μνκ² μμ±νκ³ νμ©ν μ μμ΄μ μλ μ£Όμ λ‘ λλμ΄ λ€λ€λ³΄κ³ μ ν©λλ€
μ΄λ²μλ λ°μ½λ μ΄ν°λ₯Ό μ΄ν΄νκΈ° μν μ¬μ μ§μκ³Ό, ν¨μλ‘ λ§λ λ°μ½λ μ΄ν°μ κ·Έ μ¬μ© λ°©λ² μ λν΄ μμλ³΄κ² μ΅λλ€
λ°μ½λ μ΄ν°λΌλ μ£Όμ λ₯Ό λμ΄κ°λ κ°λ
μ λν μ€λͺ
μ μ΄λμ λλ μλ΅νλλ‘ νκ² μ΅λλ€
κ·Όλ°, μ΄λ° κ°λ
λ€μ λͺ°λΌλ κ·Έλ₯ μ¨λ³΄κ³ κ³ μΉκ³ νλ©΄μ λ°°μ°λκ±° μλκΉμβ¦?
(μ λ λ©μ²ν΄μ μλ
λΆν° μ΄μ¬ν μ½μ§νκ³ μ¬ν΄κ° λμ΄μμΌ μ΄λ μ λ μ΄ν΄νμ΅λλ€!)
μκ³ κ³μλ©΄ μ΄ν΄μ λμ± λμλλ κ²λ€
*args
μ **kwargs
functools.wraps
__call__()
callable()
ν€λ νΌμ€νΈ λμμΈ ν¨ν΄ μ±
μ Decorator Pattern μμ λ‘
μΉ΄νμ μλ£ κΈ°λ³Έ λ¨μμΈ μμ€νλ μμ, μ°μ , λ¬Όμ 첨κ°λ¬Όμ λλ €κ°λ©°
μλ‘μ΄ κ°μ²΄(λΌλΌ, μΉ΄νΈμΉλ
Έ μΉ΄λΌλ© λ§ν€μλ λ±)λ₯Ό μμ±ν΄λ΄λ(μ±
μμ νμ₯νλ) λΉμ κ° μμ΅λλ€.
λ°μ½λ μ΄ν°λ₯Ό μ΄μ©ν΄, λ°λ³΅μ μ€μ΄κ³ λ©μλλ ν¨μμ μ±
μμ νμ₯νλ€λ λ©΄μμλ μ΄λμ λ λΉμ·νλ€κ³ μκ°μ΄ λλλ€.
(μλ°μ Annotation κ³Ό μκΉμλ μ μ¬νμ§λ§ νλ μΌμ λ€λ¦
λλΉ)
μλ¬΄νΌ μμ½νμλ©΄
νμ΄μ¬μ λ°μ½λ μ΄ν°λ₯Ό ν λ¨μ΄λ‘ μ 리νμλ©΄, ν΄λ‘μ μ
λλ€
μ’ λ νμ΄μ μ΄μΌκΈ° νλ©΄, ν΄λ‘μ μ μΆμ½λ¬Έλ² μ
λλ€.
λ°μ½λ μ΄ν°μ λ³Έμ§μ ν΄λ‘μ μ
λλ€. μ΄λ―Έ μκ³ κ³μλ€λ©΄ κ³Όκ°νκ² λ μ΄μ μ½μ§ μμΌμ
λ λ©λλ€!
ν΄λ‘μ κ° λλ νλ©΄ ν¨μμ ν¨μμΈκ±°μγ
γ
γ
μγ
γ
γ
γ
μ£μ‘ν©λλ€β¦ μλ μ½λλ₯Ό 보μμ Έ
# νμ€μ€ν€μ μλ
λ‘λ΄
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
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
μμ μμ λ₯Ό 보λ μ‘°κΈμ μ¬μ©ν΄μΌκ² λ€λ μκ°μ΄ λμλμ?
λ°μ½λ μ΄ν°λ μ¬μ€ μ€λ³΅λλ μ½λμ νλμ μΆμν λ°©λ²μ΄λΌκ³ μκ°ν©λλ€.
κ·Έλ¦¬κ³ μΆμνλ μΈμ λ λ€λ₯Έ λΉμ©μ μλ°ν©λλ€
μ₯μ
λ¨μ
func
λ fn
λ±μΌλ‘ λ°μμ μ€ννκΈ° λλ¬Έμ, μ΄λ€ ν¨μκ° μλ¬μΈμ§ λͺ¨νΈν¨κΈ΄ κΈ μ½μ΄μ£Όμ μ κ°μ¬ν©λλ€!πΆ
μΈμ λ μλͺ»λ λΆλΆμ΄λ μ€ν μλλ μ½λλ μ§μ ν΄ μ£Όμλ©΄ κ°μ¬νκ² μ΅λλ€
μ€μν μ¬λ¬ κ°λ
μ λ€λ£¨λ λ΄μ©μ΄λ€λ³΄λ, κ°λ
μ΄λ μλͺ»λ μ μκ° μλ€λ©΄ κΌ μλ €μ£ΌμΈμ! λ°λ‘ μμ νκ² μ΅λλ€.
κ°μΈμ μΈ μκ°μΌλ‘λ Best Practiceλ₯Ό μ°Ύμ κ·Έλλ‘ νλ €λ μκ°λλ¬Έμ
μ λ λλΆλΆμ κ°λ
λ€μ΄ 101 μμ€μ λ¨Έλ¬Όλ¬ μμλλ°
κ·Έλ₯ κ·Έλ° μκ°μμ΄ μΌλ¨ μ μ©νκ³ μ²μ²ν μμ ν΄ λκ°λ©΄μ λ§μ΄ μ΄ν΄λκ° λμμ‘λκ² κ°μ΅λλ€
μ’μ보μΈλ€λ μ΄μ λ‘ μ€,λ¨μ©νλκ²λ λ¬Έμ μΌ μ μμ§λ§ κ·Έλ¬λ©΄μ λ§μ΄ λ°°μλκ° μ μλ€κ³ μκ°νλ
μ΅ν κ°λ
μ λ§κ΅¬λ§κ΅¬ μ μ©ν΄λ³΄λ©΄ μ’μ λ― ν΄μ!
λ€μμλ ν΄λμ€ λ°μ½λ μ΄ν°μ, μΈμλ₯Ό λ°μ μ μλ λ°μ½λ μ΄ν°, μ€μ²©λ λ°μ½λ μ΄ν°μ μ¬μ© λ±μ λν΄ μ μ΄λ³΄κ² μ΅λλΉ π
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()
μμλ return wrapperμ λ€μ¬μ°κΈ°κ° μλͺ»λμ΄ λ³΄μ λλ€.
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()
μ λ€μ¬μ°κΈ°κ° μλͺ»λμ΄ μ€νλμ§ μμ΅λλ€. μλμ κ°μ΄ κ³ μ³μ£Όμλ©΄ λ€λ₯Έ λΆλ€κ»λ λμμ΄ λ λ― ν©λλ€.