2015-05-24 12 views
6

Gdy mamy do czynienia z otwartych plików, Python posiada składnię with sprawia, że ​​się, że plik zostanie zamknięty po opuszczeniu bloku - bez wyjątków itpObsługa wyjątków przy użyciu Pythona subprocess.Popen

with open('foo.txt') as f: 
    foo = f.read() 

Ponieważ procesy są zbyt zasoby , Zastanawiałem się: czy jest coś podobnego możliwego lub zalecanego przy użyciu Popen? Na przykład, czy powinno się uruchomić Popen.kill(); Popen.communicate() w klauzuli finally - zakładając, że nie mam nic przeciwko blokowaniu, dopóki proces się nie zakończy?

+1

Jeśli biegały wersji pre Pythona 3.2. możesz po prostu zdefiniować klasę za pomocą magicznych metod '__enter__' i' __exit__' do użycia 'with'. –

Odpowiedz

6

Począwszy od Python 3.2 Popen jest menedżerem kontekstu.

z docs:

POPEN obiekty są obsługiwane za pośrednictwem menedżerów kontekstowych ze stwierdzeniem: na wyjściu standardowe deskryptory plików są zamknięte, a proces czekał.

Powinno to zrobić dokładnie to, co chcesz.

Jest odpowiednia część z subprocess.py ze standardowego lib w Pythonie 3.4:

def __enter__(self): 
    return self 

def __exit__(self, type, value, traceback): 
    if self.stdout: 
     self.stdout.close() 
    if self.stderr: 
     self.stderr.close() 
    if self.stdin: 
     self.stdin.close() 
    # Wait for the process to terminate, to avoid zombies. 
    self.wait() 

Teraz można zrobić w Pythonie 2.7

from subprocess import Popen 

class MyPopen(Popen): 

    def __enter__(self): 
     return self 

    def __exit__(self, type, value, traceback): 
     if self.stdout: 
      self.stdout.close() 
     if self.stderr: 
      self.stderr.close() 
     if self.stdin: 
      self.stdin.close() 
     # Wait for the process to terminate, to avoid zombies. 
     self.wait() 

if __name__ == '__main__': 
    with MyPopen(['ls']) as p: 
     print(p) 
+0

OK, fajnie. Wygląda na to, że nie jest to zły pomysł, aby to zrobić w Pythonie 2.7, używając 'try ... finally' – z0r

+0

Dodałem wersję Pythona 2.7, kopiując kod z Pythona 3.4. Może jednak wymaga pewnych testów. ;) –

+1

@ z0r: istnieje moduł 'subprocess32', który można zainstalować w Pythonie 2.7 (zapewnia również inne ulepszenia, chociaż może nie działać w systemach innych niż POSIX). – jfs

2

Można dodać tylko dwie metody niestandardowe dowolnego klasa implementująca kompilację z instrukcją with.

class CustomObject(object): 
    def __enter__(self): 
     """ This method execudes when entering block. """ 
     return thing_you_want_to_use 

    def __exit__(self, type, value, traceback): 
     """ This method execudes on block exit. """ 
     # Tear things down. 
3

2,7 można również użyć @contextlib.contextmanager:

import contextlib 

@contextlib.contextmanager 
def manage_process(process): 
    try: 
     yield process 
    finally: 
     for stream in [process.stdout, process.stdin, process.stderr]: 
      if stream: 
       stream.close() 
     process.wait() 

np:

with manage_process(Popen(['ls'])) as p: 
    print(p)