Polecam użycie with
instrukcji Pythona do zarządzania zasobami, które wymagają oczyszczenia. Problem z używaniem wyraźnego close()
stwierdzenia polega na tym, że musisz się martwić, że ludzie w ogóle zapomną go nazwać lub zapomną umieścić go wfinally
bloku, aby zapobiec wyciekom zasobów w przypadku wystąpienia wyjątku.
Aby użyć with
instrukcji, utwórz klasę przy użyciu następujących metod:
def __enter__(self)
def __exit__(self, exc_type, exc_value, traceback)
W powyższym przykładzie użyłbyś
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)
Następnie, gdy ktoś chciałby skorzystać z twojej klasy, zrobiłby to:
with Package() as package_obj:
# use package_obj
Zmienna package_obj będzie instancją typu Package (jest to wartość zwracana przez __enter__
metodę). Jego__exit__
metoda zostanie automatycznie wywołana, niezależnie od tego, czy wystąpi wyjątek.
Możesz nawet pójść o krok dalej. W powyższym przykładzie ktoś nadal może utworzyć instancję pakietu przy użyciu swojego konstruktora bez użycia with
klauzuli. Nie chcesz, żeby tak się stało. Możesz to naprawić, tworząc klasę PackageResource, która definiuje metody __enter__
i __exit__
. Następnie klasa Package zostanie zdefiniowana ściśle wewnątrz __enter__
metody i zwrócona. W ten sposób osoba dzwoniąca nigdy nie może utworzyć instancji klasy Package bez użycia with
instrukcji:
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()
Użyłbyś tego w następujący sposób:
with PackageResource() as package_obj:
# use package_obj