Polecam używanie oświadczenia Pythona with
do zarządzania zasobami, które wymagają oczyszczenia. Problem z użyciem wyraźnego oświadczenia close()
polega na tym, że trzeba się martwić, że ludzie zapomnieli w ogóle go wywołać lub zapomnieli umieścić go w bloku finally
, aby zapobiec wyciekowi zasobów w przypadku wystąpienia wyjątku.
Aby użyć instrukcji with
utworzyć klasę z następujących metod:
def __enter__(self)
def __exit__(self, exc_type, exc_value, traceback)
W przykładzie powyżej, można użyć
class Package:
def __init__(self):
self.files = []
def __enter__(self):
return self
# ...
def __exit__(self, exc_type, exc_value, traceback):
for file in self.files:
os.unlink(file)
Potem, gdy ktoś chciał wykorzystać swoją klasę , wykonaj następujące czynności:
with Package() as package_obj:
# use package_obj
Zmienna package_obj będzie wystąpienie typu Package (jest to wartość zwrócona przez metodę __enter__
). Jego metoda __exit__
zostanie automatycznie wywołana, niezależnie od tego, czy wystąpi wyjątek.
Można nawet posunąć to podejście o krok dalej. W powyższym przykładzie ktoś mógł nadal utworzyć instancję pakietu przy użyciu swojego konstruktora bez użycia klauzuli with
. Nie chcesz, żeby tak się stało. Można to naprawić, tworząc klasę PackageResource, która definiuje metody __enter__
i __exit__
. Następnie klasa Package zostanie zdefiniowana ściśle w metodzie __enter__
i zwrócona.W ten sposób rozmówca nie mógł instancję klasy opakowania bez użycia with
oświadczenie:
class PackageResource:
def __enter__(self):
class Package:
...
self.package_obj = Package()
return self.package_obj
def __exit__(self, exc_type, exc_value, traceback):
self.package_obj.cleanup()
byłoby użyć to w następujący sposób:
with PackageResource() as package_obj:
# use package_obj
Czytanie tego, co łączyłeś, zmienne globalne odchodzą, nie ma tu zastosowania, chyba że mówisz o tym, kiedy program jest wychodzący, podczas którego myślę, że zgodnie z tym, co łączyłeś, MOŻLIWE jest, że sam moduł os jest już nie ma. W przeciwnym razie nie sądzę, że ma ona zastosowanie do zmiennych członkowskich w metodzie __del __(). –
Wyjątek jest generowany na długo przed wyjściem mojego programu. Wyjątek AttributeError, który otrzymuję, to Python, który twierdzi, że nie rozpoznaje self.files jako atrybutu Package. Być może robię to źle, ale jeśli przez "globały" nie mają znaczenia zmienne globalne względem metod (ale być może lokalne dla klasy), to nie wiem, co powoduje ten wyjątek. Wskazówki Google Python zastrzega sobie prawo do czyszczenia danych członkowskich zanim zostanie wywołany __del __ (self). – wilhelmtell
Opublikowany kod wydaje się działać dla mnie (w Pythonie 2.5). Czy możesz opublikować rzeczywisty kod, który się nie powiódł - lub uproszczony (im prostsza, lepsza wersja, która nadal powoduje błąd?) – Silverfish