문제
다음과 같은 원리를 가진 데코레이터로 사용하기위한 클래스를 구성하고 싶습니다.
- 이러한 클래스 데코레이터를 상단 1 기능에 쌓을 수 있어야합니다.
- 결과 함수 이름 포인터는 데코레이터없이 동일한 함수와 구별 할 수 없어야합니다. 어떤 유형/클래스인지 저장할 수 있습니다.
- 데코레이터를 주문하는 것은 실제로 데코레이터가 의무화하지 않는 한 관련이 없어야합니다. 즉. 독립적 인 데코레이터는 어떤 순서로든 적용 할 수 있습니다.
이것은 Django 프로젝트를위한 것이며, 지금 작업중인 특정 사례에는 2 개의 데코레이터가 필요하며 일반적인 파이썬 기능으로 나타납니다.
@AccessCheck
@AutoTemplate
def view(request, item_id) {}
@autoTemplate은 httpresponse를 반환하는 대신 컨텍스트에서 사용하기 위해 사전을 반환하도록 함수를 변경합니다. RequestContext가 사용되며 템플릿 이름은 메소드 이름과 모듈에서 추론됩니다.
@AccessCheck은 item_id를 기반으로 사용자에게 추가 점검을 추가합니다.
생성자를 제대로 얻고 적절한 속성을 복사하는 것이 단지 어떤 속성입니까?
다음과 같은 데코레이터는 다음과 같이 작동하지 않습니다.
class NullDecl (object):
def __init__ (self, func):
self.func = func
def __call__ (self, * args):
return self.func (*args)
다음 코드에서 설명한대로 :
@NullDecl
@NullDecl
def decorated():
pass
def pure():
pass
# results in set(['func_closure', 'func_dict', '__get__', 'func_name',
# 'func_defaults', '__name__', 'func_code', 'func_doc', 'func_globals'])
print set(dir(pure)) - set(dir(decorated));
또한 "인쇄 기능을 추가하십시오.이름"Nulldecl 생성자에서는 첫 번째 데코레이터에서 작동하지만 두 번째는 그렇지 않습니다. 이름이 누락 될 것입니다.
세련된 Eduffy대답은 조금 잘 작동하는 것 같습니다.
class NullDecl (object):
def __init__ (self, func):
self.func = func
for n in set(dir(func)) - set(dir(self)):
setattr(self, n, getattr(func, n))
def __call__ (self, * args):
return self.func (*args)
def __repr__(self):
return self.func
해결책
아무것도없는 데코레이터 클래스는 다음과 같습니다.
class NullDecl (object):
def __init__ (self, func):
self.func = func
for name in set(dir(func)) - set(dir(self)):
setattr(self, name, getattr(func, name))
def __call__ (self, *args):
return self.func (*args)
그런 다음 정상적으로 적용 할 수 있습니다.
@NullDecl
def myFunc (x,y,z):
return (x+y)/z
다른 팁
그만큼 데코레이터 모듈 시그니처 보존 데코레이터를 작성하는 데 도움이됩니다.
그리고 Pythondecoratorlibrary 데코레이터에게 유용한 예를 제공 할 수 있습니다.
원래 함수와 구별 할 수없는 문제에서 기능을 감싸는 데코레이터를 만들려면 사용하십시오. functools.wraps
.
예시:
def mydecorator(func):
@functools.wraps(func):
def _mydecorator(*args, **kwargs):
do_something()
try:
return func(*args, **kwargs)
finally:
clean_up()
return _mydecorator
# ... and with parameters
def mydecorator(param1, param2):
def _mydecorator(func):
@functools.wraps(func)
def __mydecorator(*args, **kwargs):
do_something(param1, param2)
try:
return func(*args, **kwargs)
finally:
clean_up()
return __mydecorator
return _mydecorator
(내 개인적인 취향은 클래스가 아닌 기능을 사용하여 데코레이터를 만드는 것입니다)
데코레이터의 순서는 다음과 같습니다.
@d1
@d2
def func():
pass
# is equivalent to
def func():
pass
func = d1(d2(func))