2011-12-20 8 views
9

Mam klasę, która opakowuje niektóre funkcje obsługi plików, których potrzebuję. Inna klasa tworzy instancję filehandler i używa jej przez nieokreślony czas. Ostatecznie, caller jest zniszczony, co niszczy jedyne odniesienie do filehandler.Zawijanie klasy wokół pliku - właściwy sposób zamykania uchwytu pliku, gdy nie ma już odwołania

Jaki jest najlepszy sposób, aby zamknąć plik filehandler?

Używam obecnie __del__(self) ale po obejrzeniu severaldifferentquestionsand articles, jestem pod wrażeniem, to jest uważany złe.

class fileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefile = open(dbf, 'rb') 
    def __del__(self): 
     self.thefile.close() 

To jest kawałek wydania instrukcji obsługi. Celem całej klasy jest usunięcie szczegółów pracy z podstawowym obiektem pliku, a także niepotrzebne przeczytanie całego pliku w pamięci. Jednak część obsługi pliku bazowego jest zamykanie go, gdy obiekt wykracza poza zakres.

Urządzenie caller nie powinno wiedzieć ani dbać o szczegóły związane z filehandler. Zadaniem filehandler jest uwolnienie wszelkich niezbędnych zasobów, gdy nie mieszczą się one w zakresie. To jeden z powodów, dla których został w ogóle wyodrębniony. Tak więc wydaje mi się, że mam do czynienia z przenoszeniem kodu filehandler do obiektu wywołującego lub radzenia sobie z nieszczelną abstrakcją.

Myśli?

Odpowiedz

11

__del__ sama w sobie nie jest złą rzeczą. Musisz tylko być bardzo ostrożnym, aby nie tworzyć cykli odniesienia w obiektach, które mają zdefiniowane __del__. Jeśli okaże się, że musisz tworzyć cykle (rodzic odnosi się do dziecka, które odnosi się do rodzica), wtedy będziesz chciał użyć modułu weakref.

Tak więc, __del__ jest w porządku, tylko uważaj na odniesienia do motocykli.

Garbage Collection: Ważną rzeczą jest to, że gdy obiekt znajdzie się poza zakresem, to może być zbierane śmieci, aw rzeczywistości będzie być zbierane śmieci ... ale kiedy? Nie ma gwarancji co do czasu, a różne implementacje Pythona mają różne cechy w tym obszarze. Aby lepiej zarządzać zasobami, lepiej jest być jednoznacznym i dodać .close() do swojego filehandler lub, jeśli jest to zgodne, dodać metody __enter__ i __exit__.

Opisane są tutaj __enter__ and __exit__ methods. Jedną z naprawdę miłych rzeczy jest to, że __exit__ jest wywoływana nawet wtedy, gdy występują wyjątki, więc możesz liczyć lub twoje zasoby są zamknięte z wdziękiem.

Twój kod, wzmocnione przez __enter__/__exit__:

class fileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefilename = dbf 
    def __enter__(self): 
     self.thefile = open(self.thefilename, 'rb') 
     return self 
    def __exit__(self, *args): 
     self.thefile.close() 

Zauważ, że plik jest otwierany w __enter__ zamiast __init__ - to pozwala na utworzenie obiektu filehandler raz, a następnie używać go w dowolnym momencie trzeba w with bez odtwarzając go:

fh = filehandler('some_dbf') 
with fh: 
    #file is now opened 
    #do some stuff 
#file is now closed 
#blah blah 
#need the file again, so 
with fh: 
    # file is open again, do some stuff with it 
#etc, etc 
+0

Ładna sztuczka z otwarciem pliku w '__enter __()' - można również zrobić trochę magii tam utrzymać pozycję pliku między otwiera/zamyka. – kindall

+1

Bardzo ładnie, to jest o wiele bliższe temu, co chciałem. Refleksy to pierwsza rzecz, którą sprawdziłem i nie mam żadnych. Ale niektóre artykuły mówią, że całe łańcuchy obiektów będą nieosiągalne, jeśli obiekt liścia ma metodę del, niezależnie od korekcji. –

+0

@SpencerRathbun: Cała dokumentacja, którą udało mi się znaleźć stwierdza, że ​​pozycje są nieściągalne ** tylko jeśli ** są cykle ref. –

6

Jak już napisałeś, klasa nie sprawi, że plik zostanie zamknięty w sposób bardziej niezawodny. Jeśli po prostu upuścisz instancję obsługi plików na poziomie podłogi, plik nie zostanie zamknięty, dopóki obiekt nie zostanie zniszczony. Może to nastąpić natychmiast lub nie, dopóki obiekt nie zostanie zebrany, ale samo upuszczenie zwykłego obiektu na podłogę spowoduje równie szybkie zamknięcie obiektu. Jeśli jedyne odniesienie do thefile pochodzi z wnętrza obiektu klasy, to gdy filehandler jest zbiorem śmieci, również zostanie usunięte i zamknięte w tym samym czasie.

Właściwy sposób korzystać z plików jest użycie oświadczenie with:

with open(dbf, 'rb') as thefile: 
    do_something_with(thefile) 

, który zagwarantuje, że thefile jest zawsze zamknięta, gdy with wyjścia klauzuli. Jeśli chcesz zawinąć pliku wewnątrz innego obiektu można zrobić też przez zdefiniowanie __enter__ i __exit__ metody:

class FileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefile = open(dbf, 'rb') 
    def __enter__(self): 
     return self 
    def __exit__(self): 
     self.thefile.close() 

a następnie można zrobić:

with FileHandler(dbf) as fh: 
    do_something_with(fh) 

i upewnij się, że plik zostanie zamknięty natychmiast .

Powiązane problemy