2014-09-24 2 views
0

오브젝트 목록 필터링을 위해 데코레이터를 사용하려고합니다. 개체 목록이 있고 정수만 필터링하고 짝수는 더 필터링해야합니다. 그리고 마지막으로 짝수를 요약하는 합계 함수를 적용해야합니다. 내 기능은 다음과 같습니다파이썬 2.7의 데코레이터 체인

def number_filter(function): 
    print 'i am number_filter and function is ' + function.__name__ 
    def wrapper3(*args, **kwargs): 
     print 'wrapper3 args: ' + repr(args) 
     l = [] 
     for a in args: 
      try: 
       l.append(int(a)) 
      except ValueError: 
       pass 
      except TypeError: 
       pass     
     return function(l) 
    return wrapper3 

def even_number_filter(function): 
    print 'i am even_number_filter and function is ' + function.__name__ 
    def wrapper1(*args, **kwargs): 
     print 'wrapper1 args: ' + repr(args) 
     l = [i for i in args if i % 2 == 0] 
     return function(l) 
    return wrapper1 

def sum_fn(args): 
    return sum(args) 

다음 호출은 독립적으로 완벽하게 작동 :

>>> number_filter(sum_fn)(1,2,'',10, {}, None) 
i am number_filter and function is sum_fn 
wrapper3 args: (1,2,'',10, {}, None) 
13 
>>> even_number_filter(sum_fn)(1,2,10) 
i am even_number_filter and function is sum_fn 
wrapper1 args: (1, 2, 10) 
12 

것은 내가 원하는 것은 결국 짝수의 요약을 얻기 위해 위에서 정의 된 두 개의 장식을 사용하는 방법입니다. 입력은 목록 (1,2,'',10, {}, None)이고 예상 출력은

추신입니다.이 문제는 실제 문제는 아니지만 해결하려고하는 것이지만 사용하려고하는 패턴과 매우 흡사합니다. 즉, 데이터를 파이프해야합니다. 내가 원하는 것을 얻기 위해 여러 필터를 통해 스트리밍하십시오. 이 문제를 해결하기 위해 일련의 책임 패턴과 유사한 체인을 만드는 것에 대해 알고 있습니다. 데코레이터를 통해 가능한지 확인하십시오.

+0

그래서 어떤 일이'(10) , {}, 없음)'? 니가 원하는게 아니야? 개인적으로 필자는 이러한 종류의 패턴을 위해 기능 스타일 프로그래밍 (예 : toolz 패키지)을 권장합니다. – mdurant

답변

2

당신은 *args 제대로 **kwargs가 (현재 풀고 하나의 시퀀스 인수 및 *args 포장/일치하지있어) 처리하도록 기능을 수정해야합니다,하지만 당신이 그 짓을했는지 일단은 둥지 장식에 쉽게 :

>>> def number_filter(function): 
    print 'i am number_filter and function is ' + function.__name__ 
    def wrapper3(*args, **kwargs): 
     print 'wrapper3 args: ' + repr(args) 
     l = [] 
     for a in args: 
      try: 
       l.append(int(a)) 
      except ValueError: 
       pass 
      except TypeError: 
       pass     
     return function(*l, **kwargs) # pass filtered args and unfiltered kwargs 
    return wrapper3 

>>> def even_number_filter(function): 
    print 'i am even_number_filter and function is ' + function.__name__ 
    def wrapper1(*args, **kwargs): 
     print 'wrapper1 args: ' + repr(args) 
     l = [i for i in args if i % 2 == 0] 
     return function(*l, **kwargs) # same again 
    return wrapper1 

>>> @number_filter # filter out non-numbers first 
@even_number_filter # then odd numbers 
def sum_fn(*args, **kwargs): # handle arbitrary arguments 
    return sum(args) 

i am even_number_filter and function is sum_fn 
i am number_filter and function is wrapper1 
>>> sum_fn(1,2,'',10, {}, None) # note separate arguments, not a single sequence 
wrapper3 args: (1, 2, '', 10, {}, None) 
wrapper1 args: (1, 2, 10) 
12 # success! 
당신의 장식 모두 비슷한 일을

주 당신은 filter_args 장식에 리팩토링 수 있도록 : 당신은`even_number_filter (number_filter (sum_fn)) (1,2, '할 때

>>> import functools 
>>> def filter_args(f): 
    def decorates(fn): 
     @functools.wraps(fn) # wrap decorators to handle docstrings 
     def wrapper(*args, **kwargs): 
      return fn(*filter(f, args), **kwargs) 
     return wrapper 
    return decorates 

>>> @filter_args(lambda i: i % 2 == 0) 
def sum_args(*args, **kwargs): 
    """Sum the positional arguments.""" 
    return sum(args) 

>>> sum_args(1, 2, 3, 4, 5) 
6