Merhaba arkadaşlar. Belki aramızda daha önce bu konuyu görmeyenler vardır, izninizle bu konudan biraz bahsetmek isterim. genelde with deyiminin sıklıkla open fonksiyonuyla kullanıldığını görüyoruz ama aslında oluşturduğumuz sınıflarda da kullanılabilir. Bu konuyla alakalı örneği aşağıda görebilirsiniz.
with deyimi ile kullanılabilir bir veri tipinin, iki tane, magic functions denilen özel metoda ihtiyacı var. Bunlardan birisi with blokuna girerken çalışacak olan __enter__, diğeri de with blokundan çıkarken çalışacak olan __exit__ magic metodu.
__exit__ magic metodunun normalde 3 tane argümanı var, sırayla bunlar;
istisna tipi anlamına gelen exc_type,
istisna değeri anlamına gelen exc_val,
istisna geri izleyici anlamına gelen exc_tb.
Bu parametreler, with blokunda eğer hata oluşturan bir durum yakalanmışsa, bu hatanın with blokundan çıkarken __exit__ metoduna aktarılmasını sağlar.
Bu parametreleri isim olarak yazmak zorunda değilsiniz, bunun yerine parametreleri temsil etmesi için *args kullanabilirsiniz. Ama __exit__ metodunun parametresi illa ki olmak zorunda.
y = 1
class Test:
def __init__(self, x):
self.x = x
self.y = y
def __enter__(self):
global y
y = self.x
def __exit__(self, *args):
global y
y = self.y
with Test(x=5):
print(y)
print(y)
Sınıflar konusunu az çok öğrenmiş olan arkadaşlar, yukarıdaki kodların ne anlama geldiğini çok rahat bir şekilde anlayacaktır.
Bu kodları çalıştırdığımız zaman with içinde y değişkeni 5'e eşitlenir. with blokundan çıkarken de y ilk haline geri döner. Tabi bu yapılan işlemi başka yollardan da yapabiliriz. Ama en azından with deyiminin kullanım alanlarından birisini daha görmüş oluyoruz.
Tabi bu __enter__ ve __exit__ metodlarının içini dilediğiniz gibi doldurabilirsiniz. Sadece basit bir örnek üzerinden göstermek istemiştim ben. Herkese iyi günler dinlerim.
Ayrıca __enter__ metodunun döndürdüğü değer with x as y ifadesindeki y oluyor, bu yüzden anlamlı bir değer döndürmek lazım. Ki bu değer çoğunlukla self oluyor.
with deyiminin içersinde bir hata yükselirse __exit__ metodunun True dönsürmesi durumunda bu hata yükseltilmiyor, False döndürmesi durumunda yükseltiliyor.
Burada sanıyorum bir yanlışlık var. __exit__ metodu True döndürse dahi, with’in içinde hata oluşturan bir satır varsa hata ekrana yazdırılır.
#!/usr/bin/python3.8
# -*- coding: utf-8 -*-
y = 1
class Test:
def __init__(self, x):
self.x = x
self.y = y
def __enter__(self):
global y
y = self.x
def __exit__(self, *args):
global y
y = self.y
print(*args)
with Test(x=5):
y += "hello"
print(y)
Pardon yanılmışım. Yukarıdaki örnekte zaten __exit__'ten None dönüyor. Mesela aşağıdaki kodlar herhangi bir hata yükseltmiyor. Çünkü dönen değer True.
y = 1
class Test:
def __init__(self, x):
self.x = x
self.y = y
def __enter__(self):
global y
y = self.x
def __exit__(self, *args):
global y
y = self.y
try:
return True
except:
print(*args)
with Test(x=5):
y += "hello"
print(y)
Weak typing’in kicimizi isirdigi bir durum. Ben bir kere bos __exit__ yazarken __enter__'a bakip “return self” ile bitirmistim. "VertexBufferObject degil bool bekliyorum" diyecegine otomacik bool() cagirdigi icin True saydi, icerdeki exception’lari yuttu. Herhalde bir 10-15 dakika “WTF?!” deyu deyu dolandim.
Sen de herhalde normalde None dondugunden ve NoneType turunde baska deger olmadigindan kelli return degerinin bir sey ifade ettigini fark etmedin. Oysa butun ornekler “return False” deseydi True oldugunda ne oldugunu merak edip bakardin—bakardik.
Yani True veren bir değer dönmek zorundaymış. İlla ki False dönmesine gerek yokmuş. İlk seferde fark etmedim. Sonra “Ya bu zaten True döndürmüyor ki, ne diye heyecan yaptım, örnek @EkremDincel’in söylediğine uyuyor.” dedim ve hatamdan dönmeye çalıştım. Böyle bilgileri hemen test edesi geliyor insanın.
Kodu merak ettim aslında. Yazdıklarından daha fazla bilgi koparabilir miyiz acaba?