2017-05-16 15 views
9

Python 2.x kod snippet'ini takip etmeyi düşünün. Ben özellikle __exit__ çağrısı hakkında ilgileniyorumİçerme bildirimi ve içerik yöneticisi __exit__ yöntemi ile içten dışa aktarma

Line 1 from file 
Before del 
__exit__ called 
After del 

: Bu komut

from __future__ import print_function 


class myfile(file): 
    def __exit__(self, *excinfo): 
     print("__exit__ called") 
     super(myfile, self).__exit__(*excinfo) 


def my_generator(file_name): 
    with myfile(file_name) as fh: 
     for line in fh: 
      yield line.strip() 


gen = my_generator('file.txt') 
print(next(gen)) 
print("Before del") 
del gen 
print("After del") 

Çıktı olan (verilen file.txt birden fazla hattı vardır).

Bu yöntemin uygulanmasını tetikleyen nedir? Bildiğimiz kadarıyla, kod hiçbir zaman with bildirimini bırakmadı (yield ifadesinden sonra "durdu" ve asla devam etmedi). Jeneratör referans sayısı 0'a düştüğünde __exit__'un çağrılması garanti edilir mi?

+2

İkincisi ikinci çağrı, henüz-olmayan-minimal bir örnekle bir artık oldu. Kod snippet'ini düzeltdim, şimdi doğru. –

+1

Bu soru sadece CPython hakkında mı? – MSeifert

+0

Öyle gözüküyordu: semantik olarak bir "nihayet" sahibi olmak benzer: https://www.python.org/dev/peps/pep-0343/ –

cevap

4

, Python çağrılarıistisnasının son yield noktasında oluşturulmamışsa, close yöntemini kullanması. Bu GeneratorExit ilerledikçe, kullandığınız içerik yöneticisinin __exit__ yöntemini tetikler. Bu, Python 2.5, in the same PEP as send and yield expressions'da tanıtılmıştır. O zamandan önce, finally ile bir try içinde yield yapamazsınız ve with ifadeleri pre-2.5 sürümünde olsaydı, yield içinden birini yapamazdınız.

1

@user2357112's answer'a eklemek için, içinde bir istisna oluştuğunda with bloğu kırılır. Bu özel durum, içerik için oluşturulan nesnenin __exit__ yöntemine iletilir.

file sınıfı, hiçbir şey sinyal vermediği için GeneratorExit istisnasından sessizce geçiyor gibi görünüyor.

class myfile(file): 
    def __exit__(self, *excinfo): 
     print("__exit__ called") 
     print(excinfo[0]) # Print the reason why the context exited 
     super(myfile, self).__exit__(*excinfo) 

Çıktı senaryonuzun: Eğer myfile.__exit__ yönteminde argc yazdırmak Ancak, bağlam doğal kapalı değildi göreceksiniz

bir jeneratör nesnenin ıslahı üzerinde
Line 1 from file 
Before del 
__exit__ called 
<type 'exceptions.GeneratorExit'> 
After del 
İlgili konular