ProgramlamaPython backend geliştirici

Bağlam yöneticileri ve contextlib modülündeki @contextmanager dekoratörü ile kaynak yöneticileri ile çalışma hakkında konuşun: neden gereklidir, nasıl çalışır ve hangi gizli sorunlar vardır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Tarihçe — Python'da kaynakları (dosyalar, bağlantılar, işlemler) yönetmek için enter, exit protokolüne dayalı with yapısı kullanılır. Basit durumlar için bir sınıf yazmak fazla, bu nedenle contextlib modülünden @contextmanager dekoratörü önerilmiştir; bu, kaynak yöneticilerini jeneratörler olarak tanımlamaya olanak tanır.

Sorun — kaynakları manuel olarak serbest bırakmak veya kapatmak rahatsız edicidir, kod hatalara karşı dayanıklı olmaz (örneğin, dosyayı kapatmayı unuttuk). Ayrıca basit şeyler için (örneğin, geçici olarak dizin veya stdout değiştirmek) iki metodu olan ayrı bir sınıf yazmak istemezsiniz.

Çözüm — @contextmanager kullanarak kaynağın "başlangıcını" ve "sonunu" ele almak, istisnaları ve serbest bırakmayı garanti eder.

Kod örneği:

from contextlib import contextmanager @contextmanager def open_file(filename, mode): f = open(filename, mode) try: yield f finally: f.close() with open_file('test.txt', 'w') as f: f.write('Hello')

Anahtar özellikler:

  • Blok başlangıcı — dönen kaynak öncesindeki her şey.
  • Blok sonu — yield'den sonraki; mutlaka hata işleme ve kapatma/serbest bırakma ile.
  • İstisna oluşsa bile kaynağın kapatılma garantisi.

Kandırmaca soruları.

@contextmanager'dan yield ile birden fazla nesne döndürmek mümkün mü (örneğin, bir demet üzerinden)?

Evet, mümkündür ve ilişkili "grup" kaynaklarını döndürmek için kullanışlıdır.

Kod örneği:

@contextmanager def managed_two(): a, b = [], {} try: yield a, b finally: a.clear(); b.clear()

Yield'den sonra bir istisna atılırsa — kaynak kapanır mı?

Evet, finally bloğu her durumda çalıştırılır, even if bir hata/istisna oluşursa with içinde.

@contextmanager tam bir sınıf bağlam yöneticisini enter/exit ile değiştirebilir mi?

Çoğu basit durumda — evet, daha karmaşık olanlarda iç içe durumlar veya miras ile çalışmak daha kolaydır sınıf üzerinden.

Yaygın hatalar ve anti-patentler

  • Finally bloğunun atlanması, hata durumunda kaynak sızıntısına yol açar.
  • Yield bir tane değil; fonksiyonda iki yield varsa bu, RuntimeError'a yol açar.
  • Jeneratör olmayan fonksiyonlarla @contextmanager kullanma girişimleri (yield yok).

Gerçek hayattan örnek

Negatif durum

Dosyayı manuel olarak açıp kapatıyorlar:

f = open('test.txt', 'w') try: f.write('Hello') finally: f.close()

Artıları:

  • Kaynağın yaşam döngüsünü yönetmede tam kontrol.

Eksileri:

  • Çok fazla şablon kodu, finally'yi unutarak hata yapma olasılığı artıyor.

Pozitif durum

Çalışma dizinini geçici olarak değiştirmek ya da dosya açmak (veya ortam ayarları): @contextmanager kullanıyorlar:

@contextmanager def work_in(dirname): import os prev = os.getcwd() os.chdir(dirname) try: yield finally: os.chdir(prev)

Artıları:

  • Kısa, başlangıç durumuna geri dönüş garantisi.

Eksileri:

  • Yüksek soyutlama seviyesi, kaynak yönetimi detaylarını gizleyebilir.