데코레이터가 변수 ‘insurance_mode’를 전송하는 데 문제가 있습니다. 나는 다음 데코레이터 문장으로 할 것입니다 :
@execute_complete_reservation(True)
def test_booking_gta_object(self):
self.test_select_gta_object()
그러나 불행히도이 진술은 효과가 없습니다. 아마도이 문제를 해결하는 더 좋은 방법이있을 것입니다.
def execute_complete_reservation(test_case,insurance_mode):
def inner_function(self,*args,**kwargs):
self.test_create_qsf_query()
test_case(self,*args,**kwargs)
self.test_select_room_option()
if insurance_mode:
self.test_accept_insurance_crosseling()
else:
self.test_decline_insurance_crosseling()
self.test_configure_pax_details()
self.test_configure_payer_details
return inner_function
답변
인수가있는 데코레이터 구문은 약간 다릅니다. 인수가있는 데코레이터는 함수를 가져 오고 다른 함수를 반환 하는 함수 를 반환해야합니다. 따라서 실제로 정상적인 데코레이터를 반환해야합니다. 약간 혼란스럽지 않습니까? 내가 말하고 싶은 건:
def decorator_factory(argument):
def decorator(function):
def wrapper(*args, **kwargs):
funny_stuff()
something_with_argument(argument)
result = function(*args, **kwargs)
more_funny_stuff()
return result
return wrapper
return decorator
여기서 당신은 주제에 대해 더 많은 것을 읽을 수 있습니다-호출 가능한 객체를 사용하여 이것을 구현하는 것도 가능합니다.
답변
편집 : 데코레이터의 정신 모델에 대한 심층적 인 이해를 위해이 멋진 Pycon Talk를 살펴보십시오 . 30 분의 가치가 있습니다.
논쟁이있는 데코레이터에 대해 생각하는 한 가지 방법은
@decorator
def foo(*args, **kwargs):
pass
로 번역
foo = decorator(foo)
데코레이터가 논쟁을한다면
@decorator_with_args(arg)
def foo(*args, **kwargs):
pass
로 번역
foo = decorator_with_args(arg)(foo)
decorator_with_args
사용자 정의 인수를 허용하고 실제 데코레이터를 리턴하는 함수입니다 (데코 레이팅 된 함수에 적용됨).
데코레이터를 쉽게 만들기 위해 부분적으로 간단한 트릭을 사용합니다.
from functools import partial
def _pseudo_decor(fun, argument):
def ret_fun(*args, **kwargs):
#do stuff here, for eg.
print ("decorator arg is %s" % str(argument))
return fun(*args, **kwargs)
return ret_fun
real_decorator = partial(_pseudo_decor, argument=arg)
@real_decorator
def foo(*args, **kwargs):
pass
최신 정보:
이상이 foo
됩니다real_decorator(foo)
함수를 꾸미는 한 가지 효과는 foo
데코레이터 선언시 이름 이 무시 된다는 것 입니다. foo
에 의해 반환되는 모든 것에 의해 “재정의”됩니다 real_decorator
. 이 경우 새로운 함수 객체입니다.
의 모든 foo
메타 데이터, 특히 docstring 및 함수 이름이 재정의됩니다.
>>> print(foo)
<function _pseudo_decor.<locals>.ret_fun at 0x10666a2f0>
functools.wraps 는 docstring과 “name”을 반환 된 함수로 “리프트”하는 편리한 방법을 제공합니다.
from functools import partial, wraps
def _pseudo_decor(fun, argument):
# magic sauce to lift the name and doc of the function
@wraps(fun)
def ret_fun(*args, **kwargs):
#do stuff here, for eg.
print ("decorator arg is %s" % str(argument))
return fun(*args, **kwargs)
return ret_fun
real_decorator = partial(_pseudo_decor, argument=arg)
@real_decorator
def bar(*args, **kwargs):
pass
>>> print(bar)
<function __main__.bar(*args, **kwargs)>
답변
IMHO가 매우 우아한 아이디어를 보여주고 싶습니다. t.dubrownik이 제안한 솔루션은 항상 동일한 패턴을 보여줍니다. 데코레이터가하는 일에 관계없이 3 층 래퍼가 필요합니다.
그래서 나는 이것이 메타 데코레이터, 즉 데코레이터를위한 데코레이터의 직업이라고 생각했습니다. 데코레이터는 함수이므로 실제로 인수를 사용하여 일반 데코레이터로 작동합니다.
def parametrized(dec):
def layer(*args, **kwargs):
def repl(f):
return dec(f, *args, **kwargs)
return repl
return layer
매개 변수를 추가하기 위해 일반 데코레이터에 적용 할 수 있습니다. 예를 들어 함수의 결과를 두 배로 만드는 데코레이터가 있다고 가정 해보십시오.
def double(f):
def aux(*xs, **kws):
return 2 * f(*xs, **kws)
return aux
@double
def function(a):
return 10 + a
print function(3) # Prints 26, namely 2 * (10 + 3)
함께 @parametrized
우리는 일반적인 구축 할 수 있습니다 @multiply
매개 변수를 가진 장식을
@parametrized
def multiply(f, n):
def aux(*xs, **kws):
return n * f(*xs, **kws)
return aux
@multiply(2)
def function(a):
return 10 + a
print function(3) # Prints 26
@multiply(3)
def function_again(a):
return 10 + a
print function(3) # Keeps printing 26
print function_again(3) # Prints 39, namely 3 * (10 + 3)
일반적으로 매개 변수화 된 데코레이터 의 첫 번째 매개 변수 는 함수이고 나머지 인수는 매개 변수화 된 데코레이터의 매개 변수에 해당합니다.
흥미로운 사용법 예제는 형식 안전 독단적 데코레이터입니다.
import itertools as it
@parametrized
def types(f, *types):
def rep(*args):
for a, t, n in zip(args, types, it.count()):
if type(a) is not t:
raise TypeError('Value %d has not type %s. %s instead' %
(n, t, type(a))
)
return f(*args)
return rep
@types(str, int) # arg1 is str, arg2 is int
def string_multiply(text, times):
return text * times
print(string_multiply('hello', 3)) # Prints hellohellohello
print(string_multiply(3, 3)) # Fails miserably with TypeError
마지막 참고 사항 : functools.wraps
래퍼 함수 에는 사용하지 않지만 항상 사용하는 것이 좋습니다.
답변
다음은 t.dubrownik ‘s answer의 약간 수정 된 버전입니다 . 왜?
- 일반적인 템플릿으로 원래 함수에서 반환 값을 반환해야합니다.
- 이것은 다른 데코레이터 / 코드에 영향을 줄 수있는 함수의 이름을 변경합니다.
그래서 사용하십시오 @functools.wraps()
:
from functools import wraps
def decorator(argument):
def real_decorator(function):
@wraps(function)
def wrapper(*args, **kwargs):
funny_stuff()
something_with_argument(argument)
retval = function(*args, **kwargs)
more_funny_stuff()
return retval
return wrapper
return real_decorator
답변
나는 당신의 문제가 데코레이터에게 인수를 전달한다고 가정합니다. 이것은 약간 까다 롭고 간단하지 않습니다.
이를 수행하는 방법의 예는 다음과 같습니다.
class MyDec(object):
def __init__(self,flag):
self.flag = flag
def __call__(self, original_func):
decorator_self = self
def wrappee( *args, **kwargs):
print 'in decorator before wrapee with flag ',decorator_self.flag
original_func(*args,**kwargs)
print 'in decorator after wrapee with flag ',decorator_self.flag
return wrappee
@MyDec('foo de fa fa')
def bar(a,b,c):
print 'in bar',a,b,c
bar('x','y','z')
인쇄물:
in decorator before wrapee with flag foo de fa fa
in bar x y z
in decorator after wrapee with flag foo de fa fa
답변
def decorator(argument):
def real_decorator(function):
def wrapper(*args):
for arg in args:
assert type(arg)==int,f'{arg} is not an interger'
result = function(*args)
result = result*argument
return result
return wrapper
return real_decorator
데코레이터 사용법
@decorator(2)
def adder(*args):
sum=0
for i in args:
sum+=i
return sum
그런 다음
adder(2,3)
생산
10
그러나
adder('hi',3)
생산
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-143-242a8feb1cc4> in <module>
----> 1 adder('hi',3)
<ipython-input-140-d3420c248ebd> in wrapper(*args)
3 def wrapper(*args):
4 for arg in args:
----> 5 assert type(arg)==int,f'{arg} is not an interger'
6 result = function(*args)
7 result = result*argument
AssertionError: hi is not an interger
답변
이것은 ()
매개 변수 를 제공하지 않아도 필요하지 않은 함수 데코레이터 용 템플리트입니다 .
import functools
def decorator(x_or_func=None, *decorator_args, **decorator_kws):
def _decorator(func):
@functools.wraps(func)
def wrapper(*args, **kws):
if 'x_or_func' not in locals() \
or callable(x_or_func) \
or x_or_func is None:
x = ... # <-- default `x` value
else:
x = x_or_func
return func(*args, **kws)
return wrapper
return _decorator(x_or_func) if callable(x_or_func) else _decorator
이에 대한 예는 다음과 같습니다.
def multiplying(factor_or_func=None):
def _decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
if 'factor_or_func' not in locals() \
or callable(factor_or_func) \
or factor_or_func is None:
factor = 1
else:
factor = factor_or_func
return factor * func(*args, **kwargs)
return wrapper
return _decorator(factor_or_func) if callable(factor_or_func) else _decorator
@multiplying
def summing(x): return sum(x)
print(summing(range(10)))
# 45
@multiplying()
def summing(x): return sum(x)
print(summing(range(10)))
# 45
@multiplying(10)
def summing(x): return sum(x)
print(summing(range(10)))
# 450