필자는 프로파일 링을 복잡하게하는 데코레이터 자체가 아니라 데코레이터가 만든 래퍼 함수을 추측합니다. 그리고 모든 래퍼 함수가 같은 이름을 가지기 때문에 이런 일이 발생합니다. 이 문제를 해결하려면 데코레이터가 래퍼 함수의 이름을 변경하게하십시오.
def decorator(func):
def wrapper(*args):
print "enter func", func.__name__
return func(*args)
wrapper.__name__ += "_" + func.__name__
return wrapper
또한 functools.wraps()
를 사용할 수 있지만 다음 래퍼 함수의 이름은 포장 년대 함수의 이름과 일치합니다. 프로필 작성에는 괜찮은 것 같아요.
이제 함수의 코드 객체에도 이름이 있습니다. 파이썬은 스택에 함수에 대한 참조를 저장하지 않고 코드 객체에만 저장합니다. 따라서 프로파일 러가 스택 프레임에서 래퍼 함수의 이름을 얻으면이 이름을 가져옵니다. 일반적인 방법으로 정의 된 래퍼는 각 래퍼 함수에 대한 코드 개체와 함수 개체를 명시 적으로 다시 작성하지 않으면 함수 개체가 다른 경우에도 코드 개체를 공유합니다. 이것은 상당히 더 많은 작업이며 매우 CPython에 특화되어있다. 그러나 여기 당신이 그것에 대해 갈 수있는 방법은 다음과 같습니다
from types import FunctionType, CodeType
def decorator(func):
def wrapper(*args):
print "enter func", func.__name__
return func(*args)
name = wrapper.__name__ + "_" + func.__name__
func_code = wrapper.func_code
new_code = CodeType(
func_code.co_argcount, func_code.co_nlocals, func_code.co_stacksize,
func_code.co_flags, func_code.co_code, func_code.co_consts,
func_code.co_names, func_code.co_varnames, func_code.co_filename,
name, func_code.co_firstlineno, func_code.co_lnotab,
func_code.co_freevars, func_code.co_cellvars)
wrapper = FunctionType(
new_code, wrapper.func_globals, name, wrapper.func_defaults,
wrapper.func_closure)
return wrapper
두 함수의 이름과 코드 객체의 이름은 wrapper_originalfuncname
여기에 설정되어 있으며 따라서 프로파일 러의 포장 기능을 별도로 계산해야한다. 원래 함수의 이름으로 쉽게 설정할 수 있으므로 런타임은 원래 함수 대신 롤백됩니다.
왜 유용하지 않습니다 (
functools.wraps
은 여전히 문서화 문자열, 모듈 이름 같은 것들의 통과 등을 허용하기 위해 여기에 사용됩니다) ? 프로파일 링 정보가 데코레이터를 가리키면 데코레이터 구현을 개선하면 커다란 변화가 일어날 수 있습니다. – jcolladojcollado : 데코레이터는 런타임의 사소한 부분이지만 callees는 그렇지 않기 때문에.이러한 호출 수신자의 "진정한 호출자"는 무엇인지 숨기며 최적화 방법을 결정할 때 중요한 정보가 될 수 있습니다. – bukzor