2017-11-16 3 views
1

Python에서 부드럽게 연결된 이터레이터 및 리소스 관리를 명확하게 표현하기가 어렵습니다.pythonic way : 반복자 체인 및 리소스 관리

아마 구체적인 예를 검사하여 명확하게됩니다

나는 유사하면서도 다른 CSV 파일의 무리에 작동이 작은 프로그램이 있습니다. 다른 동료들과 공유되기 때문에 자주 열고 닫아야합니다. 또한, 나는 그들의 콘텐츠를 변환하고 필터링해야합니다. 내가 말했듯이, 나는 그 많은을 가지고 내가했던 것보다 더 많은 복사 붙여 넣기 결국, 좋은 읽을 수있어

def doSomething(fpath): 
    with open(fpath) as fh: 
     r=csv.reader(fh, delimiter=';') 
     s=imap(lambda row: fn(row), r) 
     t=ifilter(lambda row: test(row), s) 
     for row in t: 
      doTheThing(row) 

:하지만, 그래서 나는 이런 종류의 다른 fonctions을 많이 가지고 소원. 그러나 물론 나는 반복자를 반환하는 함수에 공통 코드를 리팩토링 할 수 없습니다

def iteratorOver(fpath): 
    with open(fpath) as fh: 
     r=csv.reader(fh, delimiter=';') 
     return r #oops! fh is closed by the time I use it 

코드를 리팩토링하기위한 첫 번째 단계는 다른 '활성화 된 -'클래스를 생성하는 것입니다 :

def openCsv(fpath): 
    class CsvManager(object): 
     def __init__(self, fpath): 
      self.fh=open(fpath) 
     def __enter__(self): 
      return csv.reader(self.fh, delimiter=';') 
     def __exit__(self, type, value, traceback): 
      self.fh.close() 

다음 :

with openCsv('a_path') as r: 
    s=imap(lambda row: fn(row), r) 
    t=ifilter(lambda row: test(row), s) 
    for row in t: 
     doTheThing(row) 

하지만 단지 하나의 단계에서 각 기능의 상용구를 감소시켰다.

그런 코드를 리팩토링하는 파이썬 방법은 무엇입니까? 내 C++ 배경이 내가 생각하는 방식대로되고있다.

+0

동정 파이썬 3 사용할 수 있습니다 ...하지만 어쨌든, 당신은 그'imap' &'의 IFilter를 향상시킬 수 있습니다 '전화. 그 람다들을 제거하십시오! 대신에,'imap (fn, r)'과'ifilter (test, s)'를해라. –

답변

3

발전기을 사용할 수 있습니다. 이것들은 다른 객체에 전달할 수있는 반복 가능한 객체를 생성합니다. 예를 들어, CSV 파일의 모든 행을 산출 발전기 :

def iteratorOver(fpath): 
    with open(fpath) as fh: 
     r = csv.reader(fh, delimiter=';') 
     for row in r: 
      yield row 

루프가 with 완료 될 때까지 당신이 그것을 반복하지 않을 때는을 일시 정지 발전기 기능, 함수가 종료하지 않기 때문에 문이 파일을 닫지 않습니다.

이제 필터가 발생 사용할 수 있습니다

rows = iteratorOver('some path') 
filtered = ifilter(test, rows) 

+0

또 다른 옵션은 아마도 다른 높은 답을 쓸 가치가없는 것입니다.'fn','test' 및'doTheThing'을'doSomething'의 인수로 사용하는 것입니다. –

+1

@MarkWhitfield : 그렇지만 유연하지는 않습니다. 필터와 맵의 체인을 적용하고 싶다면 어떻게해야할까요? –

+0

불행히도, 만약 당신이 그것을 다 써 버리기 전에 (아마도 여러분이 그것을 단락 된'any'에 넣어 두었을 때) 생성기를 루핑하는 것을 멈 추면, 파일을 닫기 위해 생성기의'__del__'에 의지하게됩니다. 이는 대개 CPython에서 즉시 발생하지만 다른 Python 구현과의 미묘한 호환성 문제를 일으킬 수 있습니다. 이론적으로, 당신은'contextlib.closing (whatever_generator) '를 사용하여 할 수 있지만, 어색하고 어쨌든 그렇게하는 사람은 본 적이 없다. – user2357112