필자는 자신을 합리적으로 유능한 Python 코더로 생각하고 싶지만, 결코 그런 적이 없었던 언어의 한 측면은 데코레이터입니다.
나는 그들이 무엇인지 (피상적으로) 알고, 스택 오버플로에 대한 자습서, 예제, 질문을 읽었으며 구문을 이해하고 내 자신을 작성할 수 있으며 때로는 @classmethod 및 @staticmethod를 사용할 수 있지만 내 자신의 파이썬 코드에서 문제를 해결하는 데코레이터. “흠 … 이것은 데코레이터의 직업처럼 보입니다!”
여러분의 프로그램에서 데코레이터를 어디에서 사용했는지에 대한 예제를 제공 할 수 있을지 궁금합니다. “A-ha!” 순간과 그들을 얻을 .
답변
나는 주로 타이밍 목적으로 데코레이터를 사용합니다.
def time_dec(func):
def wrapper(*arg):
t = time.clock()
res = func(*arg)
print func.func_name, time.clock()-t
return res
return wrapper
@time_dec
def myFunction(n):
...
답변
동기화에 사용했습니다.
import functools
def synchronized(lock):
""" Synchronization decorator """
def wrap(f):
@functools.wraps(f)
def newFunction(*args, **kw):
lock.acquire()
try:
return f(*args, **kw)
finally:
lock.release()
return newFunction
return wrap
주석에서 지적했듯이 Python 2.5부터는 (또는 버전 2.6 이후) 객체 with
와 함께 명령문 을 사용하여 데코레이터의 구현을 다음과 같이 단순화 할 수 있습니다.threading.Lock
multiprocessing.Lock
import functools
def synchronized(lock):
""" Synchronization decorator """
def wrap(f):
@functools.wraps(f)
def newFunction(*args, **kw):
with lock:
return f(*args, **kw)
return newFunction
return wrap
어쨌든 다음과 같이 사용하십시오.
import threading
lock = threading.Lock()
@synchronized(lock)
def do_something():
# etc
@synchronzied(lock)
def do_something_else():
# etc
기본적으로 함수 호출의 양쪽 에 lock.acquire()
/ lock.release()
를 넣습니다 .
답변
일부 RMI를 통해 Python 메서드에 전달되는 형식 검사 매개 변수에 데코레이터를 사용합니다. 따라서 동일한 매개 변수 계산을 반복하는 대신 예외 발생 점보 점보를 반복해서 반복합니다.
예를 들어,
def myMethod(ID, name):
if not (myIsType(ID, 'uint') and myIsType(name, 'utf8string')):
raise BlaBlaException() ...
나는 단지 선언한다 :
@accepts(uint, utf8string)
def myMethod(ID, name):
...
그리고 accepts()
나를 위해 모든 작업을 수행합니다.
답변
데코레이터는 추가 기능으로 투명하게 “포장”하려는 모든 용도로 사용됩니다.
Django는이 기능을 사용하여 뷰 기능 에서 “로그인 필요”기능 을 래핑하고 필터 기능 을 등록합니다 .
클래스 데코레이터를 사용 하여 명명 된 로그를 클래스 에 추가 할 수 있습니다 .
기존 클래스 또는 함수의 동작에 “고착”할 수있는 충분히 일반적인 기능은 장식용 게임입니다.
Python-Dev 뉴스 그룹 에서 PEP 318-함수 및 메소드 데코레이터 (Decoators for Functions and Methods)가 지적한 유스 케이스에 대한 토론도 있습니다 .
답변
노즈 테스트의 경우 몇 가지 매개 변수 세트로 단위 테스트 기능 또는 방법을 제공하는 데코레이터를 작성할 수 있습니다.
@parameters(
(2, 4, 6),
(5, 6, 11),
)
def test_add(a, b, expected):
assert a + b == expected
답변
Twisted 라이브러리는 생성기와 결합 된 데코레이터를 사용하여 비동기 기능이 동기 적이라는 착각을줍니다. 예를 들면 다음과 같습니다.
@inlineCallbacks
def asyncf():
doStuff()
yield someAsynchronousCall()
doStuff()
yield someAsynchronousCall()
doStuff()
이를 사용하여 수많은 작은 콜백 함수로 나뉘어 진 코드를 단일 블록으로 자연스럽게 작성할 수 있으므로 이해하고 유지하기가 훨씬 쉽습니다.
답변
물론 로깅을위한 한 가지 용도는 다음과 같습니다.
import functools
def log(logger, level='info'):
def log_decorator(fn):
@functools.wraps(fn)
def wrapper(*a, **kwa):
getattr(logger, level)(fn.__name__)
return fn(*a, **kwa)
return wrapper
return log_decorator
# later that day ...
@log(logging.getLogger('main'), level='warning')
def potentially_dangerous_function(times):
for _ in xrange(times): rockets.get_rocket(NUCLEAR=True).fire()