2013-07-01 11 views
5

Załóżmy, że masz klasę o określonych __enter__ i __exit__ metod tak:Jak wywołać metodę __exit__ na wyjątku podczas __init__?

class MyClass: 
    def f(self): 
     raise Exception 
    def __enter__(self): 
     return self 
    def __exit__(self, type, value, traceback): 
     pass 

Jeśli wyjątek jest podniesione wewnątrz bloku with, tak:

with MyClass() as ins: 
    ins.f() 

Sposób __exit__ zostaną niejawnie zwanych , co jest bardzo miłe.

Jednak jeśli klasa jest tak:

class MyClass: 
    def __init__(self): 
     self.f() 
    def f(self): 
     raise Exception 
    def __enter__(self): 
     return self 
    def __exit__(self, type, value, traceback): 
     pass 

I oznacz ją tak:

with MyClass() as ins: 
    pass 

Gdy jest wyjątek wewnątrz metody __init__, __enter__ ma jeszcze nazwać, i __exit__ również jest nieuczciwy, co nie jest takie miłe. Jaki jest najlepszy sposób, aby temu zaradzić?

+0

Oprócz uchwycenia wyjątku w '__init __()'? –

+0

Jestem ciekawy, czy mogę uzyskać ładne ukryte przechwytywanie, które trwa, gdy wyjątek zostanie podniesiony po wywołaniu obiektu '__enter__', miejmy nadzieję, że uniknie dodatkowego bloku' try'. Być może właśnie uchwycenie wyjątku w '__init__' jest drogą do zrobienia, po prostu zastanawiam się, czy jest coś bardziej pytonowego, co pozwoli mi uniknąć konieczności duplikowania metody' __exit__'. – qwwqwwq

+2

Python nie może wywołać metody '__exit__'; jest to metoda na instancji, która nigdy nie miała szansy na dokończenie budowy. Bez instancji, bez metody "__exit__". Jedynym wyjściem jest obsłużenie wyjątku wewnątrz '.__ init __()' samemu, aby zapewnić zakończenie budowy instancji. –

Odpowiedz

4

Oczywiście nie można użyć klasy, która nie może zostać zainicjowana jako menedżer kontekstu, więc należy utworzyć instancję przed użyciem jej w bloku with.

Na przykład:

try: 
    ins = MyClass() 
except Exception as e: 
    print "Cant initiate MyClass" 
else: 
    with ins: 
     pass 

Możesz dodać dodatkowe środki, przekazując je do klasy zamiast tworzyć je podczas inicjacji:

with spawnResource() as res, MyClass(res) as y: 
    print x,y 
+0

, ale przypuśćmy, że podczas inicjacji wydarzyło się kilka rzeczy, które chcę oczyścić, jeśli inicjacja się nie powiedzie. Tj. Obiekt otwiera niektóre uchwyty plików lub coś takiego. Czy istnieje sposób, aby mieć metodę, która jest wywoływana niejawnie, gdy inicjowanie kończy się niepowodzeniem? Mogę po prostu nazwać '__exit__' jawnie, ale to wydaje mi się trochę nieprzydatne – qwwqwwq

+0

Przełącz logikę swojego kodu i najpierw odłóż zasoby, a następnie przekaż je do swojej klasy. W ten sposób możesz ponownie użyć 'with'. –

+0

ah, to zdecydowanie brzmi jak lepszy sposób podejścia do tego – qwwqwwq

2

Jak inni wskazał, że nie ma czysty sposób, ponieważ to, co próbujesz zrobić, jest niezręczne.

Prosta droga jest:

Jeśli chcesz coś czyszczone w __exit__, zainicjalizować ją __enter__.

Np.

class MyClass: 
    def f(self): 
     raise Exception 
    def __enter__(self): 
     print 'in __enter__' 
     # acquire it here... 
     return self 
    def __exit__(self, type, value, traceback): 
     print 'in __exit__' 
     # release it here... 

with MyClass() as ins: 
    print 'calling f()' 
    ins.f() 
Powiązane problemy