2012-01-03 23 views
7

this question'da, bir içerik yöneticisi içeren bir içerik yöneticisi tanımladım. Bu yuvalamayı gerçekleştirmenin en doğru yolu nedir?'u self.__enter__() numaralı telefondan aradım. Ancak, self.__exit__ numaralı telefondan, istisnanın kaldırılması durumunda son olarak bir blokta self.temporary_file.__exit__(type_, value, traceback) numaralı telefonu aramam gerektiğinden eminim. self.__exit__'da bir şeyler ters giderse type_, value ve traceback parametrelerini ayarlamalı mıyım? contextlib'u kontrol ettim, ancak bu konuda yardımcı olacak herhangi bir yardımcı program bulamadı. sorudanPython içerik yöneticilerini iç içe geçirme

Orjinal kodu:

import itertools as it 
import tempfile 

class WriteOnChangeFile: 
    def __init__(self, filename): 
     self.filename = filename 

    def __enter__(self): 
     self.temporary_file = tempfile.TemporaryFile('r+') 
     self.f = self.temporary_file.__enter__() 
     return self.f 

    def __exit__(self, type_, value, traceback): 
     try: 
      try: 
       with open(self.filename, 'r') as real_f: 
        self.f.seek(0) 
        overwrite = any(
         l != real_l 
         for l, real_l in it.zip_longest(self.f, real_f)) 
      except IOError: 
       overwrite = True 
      if overwrite: 
       with open(self.filename, 'w') as real_f: 
        self.f.seek(0) 
        for l in self.f: 
         real_f.write(l) 
     finally: 
      self.temporary_file.__exit__(type_, value, traceback) 

cevap

9

kolay yolu bağlam yöneticileri yaratmak contextlib.contextmanager beraberdir. Bunun gibi bir şey: with write_on_change_file(...) as f:'u kullanarak

@contextlib.contextmanager 
def write_on_change_file(filename): 
    with tempfile.TemporaryFile('r+') as temporary_file: 
     yield temporary_file 
     try: 
      ... some saving logic that you had in __exit__ ... 
.
with ifadesinin gövdesi yield yerine "yerine" uygulanacaktır. Vücudun içinde gerçekleşen istisnaları yakalamak istiyorsanız, yield'un kendisini try blokuna sarın.

Geçici dosya her zaman düzgün bir şekilde kapatılacaktır (with bloğu bittiğinde).

+0

Bu gerçekten çok hoş. Bu sorunun başka iyi cevaplar üretmesi durumunda soruyu bir süreliğine açık bırakacağım. –

+3

'@ contextlib.contextmanager' işlevinin kullanılması elverişli olmakla birlikte, el ile tanımlanmış' __enter__' ve '__exit__' yöntemleriyle bir sınıfın kullanılmasının uygun olduğu durumlar da vardır. Bunun hakkında herhangi bir tavsiyeniz var mı? – Zearin

+0

Peki, daha uygun olduğunda, örneğin nesnenin bir içerik yöneticisi olmaktan fazlasını yapması gerektiğinde yapın (bu durumda bir @ contextlib.contextmanager yöntemi eklemeyi düşünmeniz gerekir). –

İlgili konular