2012-11-29 2 views
1

파이썬에서 함수 목록을 클래스 속성으로 저장 한 일부 오래된 코드가 있습니다. 이러한 목록은 일종의 이벤트 후크로 사용됩니다.함수 목록을 호출하는 파이썬 one-liner

적절한 인수를 사용하여 목록의 각 함수를 호출하려면 maplambda 식을 혼합하여 한 줄짜리 함수를 사용했습니다. 지금은이 같은 lambda 표현을 사용하여 불필요한 오버 헤드가 우려하고있다. 나는 권장 된 방법은 maplambda 드롭 그냥 가독성에 대한 루프 표준을 사용하는 것 같아요.

이렇게하려면 더 나은 (더 빨리 읽는) 한 줄짜리 리더가 있습니까? 예를 들어

:

class Foo: 
    """Dummy class demonstrating event hook usage.""" 
    pre = [] # list of functions to call before entering loop. 
    mid = [] # list of functions to call inside loop, with value 
    post = [] # list of functions to call after loop. 
    def __init__(self, verbose=False, send=True): 
     """Attach functions when initialising class.""" 
     self._results = [] 
     if verbose: 
      self.mid.append(self._print) 
     self.mid.append(self._store) 
     if send: 
      self.post.append(self._send) 

    def __call__(self, values): 

     # call each function in self.pre (no functions there) 
     map(lambda fn: fn(), self.pre) 

     for val in values: 
      # call each function in self.mid, with one passed argument 
      map(lambda fn: fn(val), self.mid) 

     # call each fn in self.post, with no arguments 
     map(lambda fn: fn(), self.post) 

    def _print(self, value): 
     """Print argument, when verbose=True.""" 
     print value 

    def _store(self, value): 
     """Store results""" 
     self._results.append(value) 

    def _send(self): 
     """Send results somewhere""" 

# create instance of Foo 
foo = Foo(verbose=True) 

# equivalent to: foo.__call__(...) 
foo([1, 2, 3, 4]) 

그 한 줄을 map 전화를 쓸 수있는 더 나은 방법이 있나요?

답변

2

권장되는 방법은 당신이 주장하는 경우 map을 사용하지만 루프를 사용하는 것이 확실히, 다음 operator.methodcaller는 당신이 필요로 그냥 뭐 수 있습니다 :

>>> def foo(*args): 
... print 'foo',args 
... 
>>> def bar(*args): 
... print 'bar',args 
... 
>>> from operator import methodcaller 
>>> 
>>> map(methodcaller('__call__',1,2,3),[foo,bar]) 
foo (1, 2, 3) 
bar (1, 2, 3) 
[None, None] 

이에 대한 map 사용에 대한주의의 단어 - map이 게으른 코드가 되었기 때문에 파이썬 3에 코드를 포팅하면 작동하지 않습니다.

또한 매우 하찮게 지능형리스트를 사용하지 수 (그 또한 python3에서 작동) :

[fn() for fn in self.pre] 
[fn(val) for fn in self.mid] 

모두 "나는 불필요한 오버 헤드가 있다는 것을 걱정"의

+0

'operator.methodcaller'는 나에게 새로운 것입니다 :) 그러나 명확하게하기 위해 그것을 사용할 것이라고 확신하지 못합니다. 파이썬 3에서'map'에 대한 경고를 보내 주셔서 감사합니다. –

1

먼저 더 등등 방법을 사용하여 코드를 최적화하십시오. 프로파일 러를 사용하여 핫스팟을 찾습니다.

두 번째로, 코드는 독자가 무슨 일이 일어나는지 알려주는 설명과 함께 할 수 있습니다. 그렇지 않으면 입증 될 때까지

마지막으로, 다음 작업을 수행 할 수있는 좋은 방법입니다 : 당신이, 당신은 지능형리스트를 사용할 수있는 값을 캡처하고 싶다면

for func in self.pre: func() 
#apply every function in self.mid to every value in values 
for func,val in itertools.product(self.mid, values): 
    func(val) 

는; 평가를 지연시키고 자한다면 생성자 표현식을 사용할 수 있습니다.

+0

+1을 간단하게하기 위해 (그리고 불필요한 반환 값 목록을 작성하지 않기 위해). 하지만'zip' 대신'itertools.product'를 사용하고 싶다고 생각합니까? – moooeeeep

+0

@moooeeeep 나는 그것이 내가하는 것을 본다. 즉, OP를 두 번째 요점으로 말합니다. 코드에 주석이 필요합니다. – Marcin

+0

나는 람다 (lambda) 표현식이 cProfile 결과에서 잘리는 것을 보았습니다. 때로는 호출 된 횟수 때문에 상당히 의미있는 경우가있었습니다. 그래서 나는 물었다. 나는 너희들이 옳다고 확신한다. for 루프는 뻔뻔스럽게가는 길입니다! –

관련 문제