2014-09-03 3 views
4

나는 서로를 사용하는 간단한 함수 집합을 가지고있다. 예를 들어 :데코레이터를 사용하여 파이썬에서 "확장"시간 모니터링을 수행 할 수 있습니까?

def func(x) 
    y = func_1(x) 
    z = func_2(y) 
    return z 

def func_1(x): 
    return x + 1 

def func_2(x) 
    a = func_a(x) 
    b = func_b(y) 
    return b 

당신이 볼 수있는 바와 같이, func는 그 차례로, func_1func_2func_2를 사용 func_afunc_b을 사용하여 "루트"기능입니다. func으로 전화하면 결과로 z가 표시됩니다.

이제 장식자를 사용하여 내 기능을 "수정"하거나 "확장"하고 싶습니다. 결과적으로 (func의 결과로) 나는 z을 얻었을뿐 아니라 얼마나 걸렸는지를 보여주는 객체를 얻습니다. 이 기능을 실행하고 기능에 의해 사용 된 기능과 이들 "하위 기능"을 실행하는 데 걸린 시간, "하위 기능"및 "기능"이 사용한 하위 기능을 실행하십시오. 오랫동안 그것을 실행하는 데 걸렸습니다. 그것이 내가 내가 "추가"결과 기대의 예를 제공 간단하려면 : 위의 예에서

{ 
    'fname' : 'func', 
    'etime' : 12.000, 
    'subs' : [ 
     { 
     'fname' : 'func_1', 
     'etime' : 2.000, 
     'subs' : [] 
     }, 
     { 
     'fname' : 'func_2', 
     'etime' : 10, 
     'subs' : [ 
      { 
      'fname' : 'func_a', 
      'etime' : 6, 
      'subs' : [] 
      }, 
      { 
      'fname' : 'func_b', 
      'etime' : 4 
      'subs' : [] 
      } 
     ] 
     } 
    ] 
} 

을 "에 fname"는 함수의 이름을 의미한다 "etime이는"그것을 어떻게 긴 실행 시간을 (의미 이 함수를 실행하는 데 걸리는 시간), "subs"는 고려 된 함수에서 사용 된 하위 함수의 목록입니다. 각 하위 기능에 대해 동일한 키 ("fname", "etime", "subs")가 있습니다. 그래서 이것은 "재귀적인"구조입니다. 함수가 어떤 함수도 사용하지 않았다면 "subs"는 빈리스트에 매핑됩니다.

def decorate(func): 

    def wrapper(*args, **kw): 

     d = {} 
     d['fname'] = func.__name__ 
     t0 = time.time() 

     out = func(*args, **kw) 

     d['etime'] = time.time() - t0 

     d['subs'] = ? 

     ?.append(d) 

    return wrapper 

을하지만 나는 더 구현 스택 :

나는 다음과 같은 장식과 함께 시작했습니다. 나는 해결책을 찾을 수 없으며 그것이 가능하다는 것을 확신하지 못한다.

아이디어는 데코레이터를 사용하여 각 함수에 전달 된 인수의 수를 늘리는 것입니다. 각 함수는 지금까지 사용 된 모든 하위 함수를 포함하는 빈 목록을 가져 와서이 목록에 추가합니다.

+2

데코레이터는 함수를 둘러 쌉니다. 인자는 인자 (arguments)를보고 다시 호출 ('return' 값)하지만 호출하지 않습니다. 데코레이터를 사용하여이 작업을 수행하려면 여러 함수 호출간에 상태를 공유하는 것과 관련된 모든 함수를 래핑해야합니다. 또는 기존 프로파일 러를 사용하십시오. – jonrsharpe

+5

당신의 질문이 합법적이지는 않겠지 만, 당신은 꽤 많이 바퀴를 재발 명하고 있습니다. ['profilestats'] (https : //pypi.python)의'@profile' 데코레이터입니다.org/pypi/profilestats /) 패키지는 이것을 정확히 수행합니다. 또한 [이 답변] (http://stackoverflow.com/questions/19857749/what-is-the-reliable-method-to-find-most-time-consuming-part-of-the-code/19857889#19857889)을 참조하십시오.)에서 사용 예제와 몇 가지 세부 정보를 확인할 수 있습니다. –

+0

@ jonrsharpe, 알아요. 그러나 각 함수가 인수에서 동일한 모든 객체를 모든 하위 함수로 전달하고 각 하위 함수가이 객체에 무언가를 쓴다면 데코레이터에서 래핑 된 함수를 실행 한 후 하위 함수가 작성한 정보를 얻습니다. – Roman

답변

3

제안 된대로 실제 프로파일 러를 사용하는 것이 좋습니다.

여전히 데코레이터 클래스를 사용하여 수행 할 수 있습니다. 모든 데코레이터의 인스턴스간에 공유되는 스택을 사용하여 서브 목록을 추적 할 수 있습니다.

class profile(object): 
    #class variable used as a stack of subs list 
    stack = [[]] 

    def __init__(self, f): 
     self.f = f 

    def __call__(self, *args, **kw): 
     func = dict(fname = self.f.__name__) 

     #append the current function in the latest pushed subs list 
     profile.stack[-1].append(func) 

     #push a new subs list in the stack 
     profile.stack.append([]) 

     #execution time of the actual call 
     t0 = time.time() 
     out = self.f(*args, **kw) 
     func['etime'] = time.time() - t0 

     #pull the subs list from the stack 
     func['subs'] = profile.stack.pop() 

     return out 

    @classmethod 
    def show(cls): 
     import json #useful to prettify the ouput 
     for func in cls.stack[0]: 
      print json.dumps(func, sort_keys=True, indent=4) 

당신은 당신이 @profile와 프로필에 표시 할 모든 기능을 장식해야합니다. 실제 상황에서는 데코 레이팅 된 함수가 실패 할 때 예외를 처리 할 수 ​​있습니다.

OUPUT는 :

profile.show() 모두 자신의 내면을 '호출로 프로파일 모든 소위'루트 '기능의 목록을 보여줍니다.

{ 
    "etime": 4.5, 
    "fname": "func", 
    "subs": [ 
     { 
      "etime": 1.0, 
      "fname": "func_1", 
      "subs": [] 
     }, 
     { 
      "etime": 3.5, 
      "fname": "func_2", 
      "subs": [ 
       { 
        "etime": 1.5, 
        "fname": "func_a", 
        "subs": [] 
       }, 
       { 
        "etime": 2.0, 
        "fname": "func_b", 
        "subs": [] 
       } 
      ] 
     } 
    ] 
} 
+0

나는 그것이 거꾸로 생각한다. 인수를 데코레이터 클래스에 전달할 때 함수가 __call__에 전달되지 않고 args가 __init__에 전달되지 않습니까? – tsalaroth

+0

데코레이터에 인수가없는 경우가 아니라면 함수 f가 꾸며질 때'__init__'이 호출되고 f가 호출 될 때마다'__call__'이 호출됩니다. – sebdelsol

+1

함수 호출이 실패 할 경우를 대비하여 아마도'try/except' 논리를 사용하려고했습니다. – acushner

관련 문제