앗! 광고가 차단되었어요!
글 내용이 방문자께 도움이 되었다면, 광고 차단 프로그램 해제를 고려해주세요 😀.

오늘은 데코레이터의 예를 살펴보기로 했습니다.
먼저 데코레이터에 대해서 살펴볼까요?
Decorator with @
Syntax
The current syntax for function decorators as implemented in Python 2.4a2 is:
@dec2
@dec1
def func(arg1, arg2, ...):
pass
This is equivalent to:
def func(arg1, arg2, ...):
pass
func = dec2(dec1(func))
without the intermediate assignment to the variable func. The decorators are near the function declaration. The @ sign makes it clear that something new is going on here.
데코레이터는 객체를 감싸는 객체를 의미합니다. 감쌀 대상이 함수라면 함수 데코레이터, 클래스라면 클래스 데코레이터라고 합니다.
파이썬에서는 @
syntax를 이용하면, 자동으로 감싸진 객체를 반환하게 됩니다.
위 예에서 볼 수 있듯이, func
는 dec2(dec1(func))
로 정의되며, func(...)
는 dec2(dec1(func))(...)
의 결과를 반환할 것입니다.
또 인자를 받아 데코레이터를 반환하는 함수를 사용할 수도 있습니다.
The current syntax also allows decorator declarations to call a function that returns a decorator:
@decomaker(argA, argB, ...)
def func(arg1, arg2, ...):
pass
This is equivalent to:
func = decomaker(argA, argB, ...)(func)
First Example: @onexit
def onexit(f):
import atexit
atexit.register(f)
return f
@onexit
def func():
...
func = onexit(func)
이므로 onexit
으로 데코레이팅 된 함수는 애플리케이션이 종료될 때 호출될 것입니다.
Note that this example is probably not suitable for real usage, but is for example purposes only.
다만 이런 예는 실제 적용하기는 어려울 수도 있다고 하네요.
Second Example: @singleton
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
MyClass = singleton(MyClass)
이므로 MyClass()
는 cls
가 MyClass
인 getinstnace()
가 됩니다. MyClass()
는 언제나 instances
에 저장된 객체를 반환할 것입니다.
Third Example: @attrs
def attrs(**kwds):
def decorate(f):
for k in kwds:
setattr(f, k, kwds[k])
return f
return decorate
@attrs(versionadded="2.2",
author="Guido van Rossum")
def mymethod(f):
...
함수에 속성을 추가하는 경우입니다. 위에서 추가하는 속성 versionadded, author
등은 문서화할 때 사용될 것 같네요. 함수 내부에서 설정할 필요 없이 데코레이터로 일괄 적용할 수 있겠습니다.
Fourth Example: @accepts, @returns
네 번째 예시는 데코레이팅 된 함수의 인자와 반환 값을 검사하는 데코레이터입니다.
def accepts(*types):
def check_accepts(f):
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_accepts
def returns(rtype):
def check_returns(f):
def new_f(*args, **kwds):
result = f(*args, **kwds)
assert isinstance(result, rtype), \
"return value %r does not match %s" % (result,rtype)
return result
new_f.func_name = f.func_name
return new_f
return check_returns
@accepts(int, (int,float))
@returns((int,float))
def func(arg1, arg2):
return arg1 * arg2
func
는 아래와 같이 됩니다.
func = accepts(int, (int, float))(
returns((int, float))(func))
func
호출 시 주어지는 인자는 accepts
에 의해 검사되고, 반환되는 값은 returns
에 의해 검사됩니다. assert
을 사용했기 때문에 타입이 맞지 않으면 에러가 발생합니다.
Fifth Example: @provides
다섯번째 예시는 인터페이스와 관련된 것으로, PyProtocols
와 연관이 있다고 합니다. (PEAK, Pyprotocols 이런 용어가 나오는 데 저는 처음 들어보네요)
def provides(*interfaces):
"""
An actual, working, implementation of provides for
the current implementation of PyProtocols. Not
particularly important for the PEP text.
"""
def provides(typ):
declareImplementation(typ, instancesProvide=interfaces)
return typ
return provides
class IBar(Interface):
"""Declare something about IBar here"""
@provides(IBar)
class Foo(object):
"""Implement something here..."""
대부분 아시겠지만 파이썬에는 인터페이스 키워드가 없습니다. 작성하면서 알았는데 인터페이스 기능을 추가하는 PEP 245는 있지만 Rejected 상태입니다.
이번 예시는 이를 보완하는 데코레이터를 정의하는 것으로 보입니다.
상세한 코드 구현은 아니지만, 클래스가 *interfaces
들을 구현/implements 한다의 느낌으로 이해했습니다.
References
'공돌이' 카테고리의 다른 글
C, TCP 기반으로 간단한 HTTP 서버 작성하기 (1) | 2020.11.22 |
---|---|
문서화를 위한 drf-yasg 적용하기 (2) | 2020.10.26 |
Python: Context Manager (0) | 2020.10.26 |
Python: Generator (0) | 2020.10.26 |
Coursera 재정지원 (Financial Aid) 요청하기 (0) | 2020.07.26 |