다음 두 코드는 거의 동일하다는 것이 잘 알려져 있습니다.
@dec
def foo():
pass foo = dec(foo)
############################################
foo = dec(foo)
가장 일반적인 실수는 @
단순히 가장 왼쪽의 주장을 숨기는 것이라고 생각하는 것입니다 .
@dec(1, 2, 3)
def foo():
pass
###########################################
foo = dec(foo, 1, 2, 3)
위의 방법이 효과적이라면 데코레이터를 작성하는 것이 훨씬 쉬울 것 @
입니다. 불행히도, 그것은 일이 끝나는 방식이 아닙니다.
Wait
몇 초 동안 프로그램 실행을 방해 하는 데코레이터 를 생각해보십시오 . 대기 시간을 전달하지 않으면 기본값은 1 초입니다. 사용 사례는 다음과 같습니다.
##################################################
@Wait
def print_something(something):
print(something)
##################################################
@Wait(3)
def print_something_else(something_else):
print(something_else)
##################################################
@Wait(delay=3)
def print_something_else(something_else):
print(something_else)
때 Wait
같은 인수,이 @Wait(3)
다음 호출이 Wait(3)
실행 되기 전에 다른 어떤 일이 발생합니다.
즉, 다음 두 코드는 동일합니다.
@Wait(3)
def print_something_else(something_else):
print(something_else)
###############################################
return_value = Wait(3)
@return_value
def print_something_else(something_else):
print(something_else)
이것은 문제입니다.
if `Wait` has no arguments:
`Wait` is the decorator.
else: # `Wait` receives arguments
`Wait` is not the decorator itself.
Instead, `Wait` ***returns*** the decorator
하나의 솔루션이 아래에 나와 있습니다.
다음과 같은 클래스를 만들어 보자 DelayedDecorator
.
class DelayedDecorator:
def __init__(i, cls, *args, **kwargs):
print("Delayed Decorator __init__", cls, args, kwargs)
i._cls = cls
i._args = args
i._kwargs = kwargs
def __call__(i, func):
print("Delayed Decorator __call__", func)
if not (callable(func)):
import io
with io.StringIO() as ss:
print(
"If only one input, input must be callable",
"Instead, received:",
repr(func),
sep="\n",
file=ss
)
msg = ss.getvalue()
raise TypeError(msg)
return i._cls(func, *i._args, **i._kwargs)
이제 다음과 같이 쓸 수 있습니다 :
dec = DelayedDecorator(Wait, delay=4)
@dec
def delayed_print(something):
print(something)
참고 :
dec
여러 인수를 허용하지 않습니다.
dec
랩핑 된 함수 만 허용합니다.
import inspect 클래스 PolyArgDecoratorMeta (type) : def call (Wait, * args, ** kwargs) : try : arg_count = len (args) if (arg_count == 1) : if callable (args [0]) : SuperClass = inspect. getmro (PolyArgDecoratorMeta) [1] r = 수퍼 클래스. 요구 (기다린 인수 [0]) 또, R = DelayedDecorator (기다린 인수 *, ** kwargs로) 다른 마지막으로 R = DelayedDecorator (기다린 인수 *, ** kwargs로) 통과 복귀 R
가져 오기 시간 클래스 Wait (metaclass = PolyArgDecoratorMeta) : def init (i, func, delay = 2) : i._func = func i._delay = delay
def __call__(i, *args, **kwargs):
time.sleep(i._delay)
r = i._func(*args, **kwargs)
return r
다음 두 코드는 동일합니다.
@Wait
def print_something(something):
print (something)
##################################################
def print_something(something):
print(something)
print_something = Wait(print_something)
"something"
다음과 같이 콘솔에 매우 느리게 인쇄 할 수 있습니다 .
print_something("something")
#################################################
@Wait(delay=1)
def print_something_else(something_else):
print(something_else)
##################################################
def print_something_else(something_else):
print(something_else)
dd = DelayedDecorator(Wait, delay=1)
print_something_else = dd(print_something_else)
##################################################
print_something_else("something")
최종 노트
이 코드를 많이 보일 수도 있지만, 당신은 클래스를 작성하지 않아도 DelayedDecorator
및 PolyArgDecoratorMeta
모든 시간을. 다음과 같이 개인적으로 작성해야하는 유일한 코드는 상당히 짧습니다.
from PolyArgDecoratorMeta import PolyArgDecoratorMeta
import time
class Wait(metaclass=PolyArgDecoratorMeta):
def __init__(i, func, delay = 2):
i._func = func
i._delay = delay
def __call__(i, *args, **kwargs):
time.sleep(i._delay)
r = i._func(*args, **kwargs)
return r
execute_complete_reservation
두 개의 매개 변수를 사용하지만 하나를 전달합니다. 데코레이터는 다른 함수 안에 함수를 감싸는 구문 설탕입니다. 전체 설명서는 docs.python.org/reference/compound_stmts.html#function 을 참조하십시오 .