with deyimine, Python'da kaynakları ele almanın özlü bir yoluna, zaten aşina olabilirsiniz. Peki perde arkasında nasıl çalıştığını hiç merak ettiniz mi? with anahtar sözcüğünün gücü context manager'lardan gelir.
Context manager'lar, Python'da kaynak yönetimine yapılandırılmış bir yaklaşım sunan temel bir tasarım kalıbıdır. Kaynakların edinilmesini, doğru şekilde kullanılmasını ve hatalar ya da istisnalar olsa bile en sonunda serbest bırakılmasını veya temizlenmesini garanti ederler.
Bu, dosyalar, ağ bağlantıları veya veritabanı tanıtıcıları gibi kaynaklarla çalışırken özellikle önemlidir. Context manager kullanarak, bir dosyayı kapatmayı ya da bir kilidi serbest bırakmayı unutma endişesinden kurtularak daha temiz ve güvenilir kod yazabiliriz.
Bu eğitimde, Python'un varsayılan olarak sunduğu context manager'ların ötesine geçerek kendi context manager'larımızı yazmayı öğreneceğiz.
Python'da Context Manager'ları Anlamak
Perde arkasında, context manager'lar iki özel yöntemi tanımlayan nesnelerdir: __enter__ ve __exit__. __enter__ yöntemi, with bloğuna girdiğinizde çağrılır ve dönüş değeri bu blok içindeki bir değişkene atanır. Öte yandan __exit__ yöntemi, with bloğu normalde ya da bir istisnayla sona erse de çağrılır.
Bu yapı, doğru kaynak yönetimini sağlar. Bunu daha iyi anlamak için Python'daki bazı yerleşik context manager'lara bakalım:
withopen('file.txt','r')asfile:
data =file.read()Altyapı:
Burada, open('file.txt', 'r') bir context manager olarak davranır. with bloğuna girdiğinizde, dosya nesnesinin enter yöntemi çağrılır, dosya açılır ve file değişkenine atanır. Ardından dosya içeriğine erişmek için file.read() kullanabilirsiniz.
Sonrasında, dosya nesnesinin __exit__ yöntemi, with bloğu çıkarken bir istisna oluşsa bile mutlaka çağrılır. Bu yöntem, dosyayı kapatmakla ilgilenir; böylece açık dosya tanıtıcıları bırakmamış olursunuz.
2. İş Parçacığı Kilitleme
Dosyaların ötesinde, context manager'lar threading.Lock() kullanılarak iş parçacığı eşzamanlaması için de kullanılabilir:
import threading
lock = threading.Lock()with lock:# Critical sectionprint("This code is executed under lock protection.")Altyapı:
Burada, lock bir threading.Lock nesnesi, yani başka bir context manager'dır. with bloğuna girdiğinizde __enter__ yöntemi kilidi edinir, böylece aynı anda yalnızca bir iş parçacığı kritik bölümü çalıştırabilir. Son olarak, with bloğundan çıkarken __exit__ yöntemi kilidi serbest bırakır ve diğer iş parçacıklarının devam etmesine izin verir.
3. Veritabanı Bağlantıları
Benzer şekilde, context manager'lar veritabanı bağlantılarını da yönetebilir:
import sqlite3
with sqlite3.connect('database.db')as connection:
cursor = connection.cursor()
cursor.execute("SELECT * FROM table")
rows = cursor.fetchall()Altyapı:
sqlite3.connect('database.db') çağrısı bir context manager'dır. with bloğuna girildiğinde veritabanına bir bağlantı kurulur ve connection değişkenine atanır. Ardından veritabanıyla etkileşim kurmak için bir cursor kullanabilirsiniz. with bloğundan çıkarken __exit__ yöntemi bağlantının kapatılmasını garanti eder ve kaynak sızıntılarını önler.
4. Ağ Soketleri
Context manager'lar ağ iletişimini bile ele alabilir:
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM)as s:
s.connect(('localhost',8080))
s.sendall(b'Hello, world')
data = s.recv(1024)Altyapı:
Burada, socket.socket(socket.AF_INET, socket.SOCK_STREAM) bir context manager gibi davranan bir soket nesnesi oluşturur. __enter__ yöntemi soketi oluşturur; with bloğu içinde bağlanabilir, veri gönderebilir ve alabilirsiniz. __exit__ yöntemi iş bittiğinde soketin düzgün şekilde kapatılmasını sağlar.
5. Dizin Taraması
Bu kez, os.scandir('.') dizin girdileri üzerinde yineleme yapmanın bir yolunu sağlar:
with os.scandir('.')as entries:for entry in entries:print(entry.name)Altyapı:
Burada os.scandir('.') context manager olarak davranır. __enter__ yöntemi bir dizin taraması açar ve with bloğu içinde girdiler üzerinde yineleme yapabilirsiniz. __exit__ yöntemi çıkışta dizin taramasını temizler.
Gördüğünüz gibi, context manager'ların gücüyle with deyimi, ayırma ve geri alma işlemlerini otomatikleştirerek kaynak yönetimini basitleştirir.
Python'da özel context manager yazmak
Şimdi, kaynak yönetimi üzerinde daha ince ayarlı denetim sağlamak için kendi özel manager'larınızı nasıl yazacağınıza bakalım.
Özel context manager yazmanın iki temel yaklaşımı vardır: sınıf tabanlı ve fonksiyon tabanlı.
Sınıf Tabanlı Yaklaşım
Sınıf tabanlı yaklaşım, context manager yazmanın en yapılandırılmış ve esnek yöntemidir. Burada, __enter__ ve __exit__ özel yöntemlerini uygulayan bir sınıf tanımlarsınız.
Bir çalıştırma süresini ölçen Timer sınıfı örneğine bakalım:
import time
classTimer:def__enter__(self):
self.start_time = time.time()return self
def__exit__(self, exc_type, exc_value, traceback):
self.end_time = time.time()
elapsed_time = self.end_time - self.start_time
print(f"Elapsed time: {elapsed_time} seconds")# Example usageif __name__ =="__main__":with Timer()as timer:# Code block to measure the execution time
time.sleep(2)# Simulate some time-consuming operation
Elapsed time:2.002082347869873 seconds
Altyapı:
Burada, Timer sınıfı, with bloğuna girildiğinde başlangıç zamanını yakalamak için __enter__ yöntemini tanımlar. Blok içinde nesneye erişim sağlamak üzere self döndürülür. __exit__ yöntemi, with bloğundan çıkarken geçen süreyi hesaplar ve yazdırır.
Fonksiyon Tabanlı Yaklaşım
Daha kısa ama esneklikten ödün verebilecek bir yaklaşımı tercih ediyorsanız, fonksiyon tabanlı yöntem iyi bir seçenek olabilir. Burada, herhangi bir fonksiyonu bir context manager'a dönüştürmek için contextlib modülündeki contextmanager dekoratörünü kullanırsınız.
@contextmanager dekoratörü, timer fonksiyonunu bir context manager'a dönüştürür. Fonksiyon içinde start_time yakalanır ve yield ifadesi yürütmeyi durdurur; böylece with bloğu içindeki kod çalışır.
Son olarak, bitiş zamanı yakalanıp geçen süre yazdırılarak __exit__ işlevselliği sağlanır.
Özetle, __enter__ mantığını yield'dan önce, __exit__ mantığını ise sonrasına yazarsınız. Her iki yaklaşım da aynı sonucu elde eder; seçim yapınız yapı ve okunabilirlik tercihlerinize bağlıdır.
Context Manager'ların Pratik Örnekleri
Artık Python'da özel context manager yazmayı anladığınıza göre, son derece faydalı olabilecek bazı pratik örneklere bakalım.
Dosya İşlemlerini Yönetmek
Dosya işlemleri birçok uygulamada yaygındır. Dosyalardan okuma ya da dosyalara yazma fark etmeksizin, doğru yönetim veri bütünlüğünü ve kaynak verimliliğini sağlar. Özel bir context manager kullanarak bir dosyaya metin yazmak istediğimiz bir senaryoyu düşünelim.
Bu örnekte, dosya işlemlerini ele alan Python'daki open işlevini taklit etmek için bir FileManager sınıfı tanımlıyoruz. Her yöntemin ne yaptığını parçalayalım:
__init__(self, filename, mode): Bu yöntem sınıfın kurucusudur. Açılacak dosyayı ve hangi kipte açılacağını (ör. okuma, yazma, birleştirme) belirten filename ve mode ile FileManager nesnesini başlatır.
__enter__(self): Her zamanki gibi, with bloğuna girildiğinde çağrılır. filename ile belirtilen dosyayı, mode ile belirtilen kipte açar. Açılan dosya nesnesi self.file'a atanır ve with bloğu içinde kullanılmak üzere döndürülür.
__exit__(self, exc_type, exc_value, traceback): Blok içinde bir istisna oluşup oluşmadığına bakılmaksızın, with bloğundan çıkarken çağrılır. self.fileNone değilse self.file.close() çağrılarak dosyanın düzgün şekilde kapatılmasını sağlar. Bu, kaynak sızıntılarını engeller ve doğru temizliği garanti eder.
Yukarıdaki kodu çalıştırdıktan sonra example.txt içeriğini incelerseniz, yazılan metni görmelisiniz:
Elbette, FileManager sınıfının avantajı, dosyalarla çalışmak için istediğiniz özel mantığı uygulayabilmenizdir. Örneğin, açılan veya kapatılan dosyaların bir metin dosyasına kaydını tutacak şekilde sınıfı değiştirebilirsiniz.
Zaman damgalarıyla çalışmak için datetime modülü içe aktarılır.
Dosya işlemlerini günlüğe kaydetmek için log_action yöntemi eklenir.
Günlük dosyasının adını belirlemek için log_filename parametresi eklenir. Varsayılan değer 'file_log.txt' olarak ayarlanır.
__enter__ ve __exit__ yöntemleri içinde log_action kullanılarak dosya adı ve eylem (açıldı ya da kapatıldı) günlük dosyasına eklenir.
log_action içinde, geçerli zaman damgasını "YYYY-MM-DD HH:MM:SS" biçiminde almak için datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") kullanılır.
Zaman damgası, dosya adı ve eylemle birlikte günlüğe eklenir.
Bu yine sqlite3.connect işlevini taklit eder, ancak özel veritabanı yönetim mantığı eklenerek daha da iyileştirilebilir. Yöneticinin çalışıp çalışmadığını bazı örnek işlevlerle kontrol edelim:
# Example usagedefcreate_table():with DatabaseConnection("example.db")as connection:
cursor = connection.cursor()
cursor.execute("""CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
username TEXT,
email TEXT)""")definsert_data(username, email):with DatabaseConnection("example.db")as connection:
cursor = connection.cursor()
cursor.execute("INSERT INTO users (username, email) VALUES (?, ?)",(username, email))
connection.commit()deffetch_data():with DatabaseConnection("example.db")as connection:
cursor = connection.cursor()
cursor.execute("SELECT * FROM users")return cursor.fetchall()if __name__ =="__main__":
create_table()
insert_data("john_doe","[email protected]")
insert_data("jane_doe","[email protected]")
users = fetch_data()print("Users in the database:")for user in users:print(user)
Users in the database:(1,'john_doe','[email protected]')(2,'jane_doe','[email protected]')(3,'john_doe','[email protected]')(4,'jane_doe','[email protected]')Altyapı:
Veritabanı işlemlerini işlevlere bölerek ve az önce oluşturduğumuz özel yöneticiyi kullanarak çok daha sürdürülebilir kod yazabiliriz.
Bu bölümde, Python'da context manager'larla ilgili ileri düzey konuları ele alacağız. Bunlar arasında hata yönetimi ve iç içe context manager kullanımı yer alır.
Hata yönetimi
Hata yönetimi programlamanın temel bir yönüdür ve Python'daki context manager'lar, kaynak yönetimi işlemleri içinde hataları yönetmek için kullanışlı bir yol sunar.
FileManager sınıfı örneğinde, bir istisna oluşsa bile doğru temizliği sağlamak için __exit__ yönteminin içinde hata yönetimi uygulanabilir. Örneğin, dosyaya veri yazılırken (yani with bloğu içindeyken) bir hata oluşursa, kaynak sızıntılarını önlemek için dosyanın yine de kapatılmasını isteriz. __exit__ yöntemini şu şekilde değiştirebiliriz:
Burada, önce doğru temizliği sağlamak için self.file.close() ile dosyayı kapatıyoruz. Ardından bir istisna olup olmadığını kontrol ediyoruz (exc_type is not None). Eğer varsa, neyin yanlış gittiğine dair geri bildirim sağlamak için bir hata mesajı yazdırıyoruz.
Burada:
exc_type, AttributeError ve IndexError gibi istisna sınıfıdır.
exc_value, mesajı içeren istisna örneğidir.
traceback, hatanın tam iz bilgisidir.
Şimdi, bilerek hatalı bir kodla FileManager sınıfını çalıştıralım:
with FileManager("example.txt","r")asfile:# Simulate a sample error
content =file.read()print(content[150])
An error occurred: string index out of rangeAltyapı:
Dolayısıyla, özel yöneticilerinizde istisnaları ele alırken özel mantık uygulamak için aşağıdaki örnek iş akışını takip edebilirsiniz:
def__exit__(self, exc_type, exc_value, traceback):# Perform cleanup...# Handle the exceptionifisinstance(exc_value, AttributeError):# Handle AttributeError hereprint(f"Exception message: {exc_value}")# Handle another exceptionelifisinstance(exc_value, AnotherError):...Altyapı:
Context manager'ları iç içe kullanmak
Context manager'ları iç içe kullanmak, tek bir with deyimi içinde, her biri kendi context manager'ına sahip birden fazla kaynağı aynı anda yönetmenizi sağlar. Bu, birden fazla kaynağı içeren karmaşık işlemlerle uğraşırken özellikle kullanışlıdır. Örneklerimizde context manager'ları nasıl iç içe kullanabileceğimize bakalım.
Örneğin, aynı bağlam içinde bir dosya açmak ve veritabanı işlemleri yapmak isteyebiliriz. Belki de bir CSV dosyasının içeriğini satırlar halinde bir veritabanına aktarmak istiyoruz. Bunu tek bir with deyimi içinde FileManager ve DatabaseConnection context manager'larını iç içe kullanarak başarabiliriz:
if __name__ =="__main__":with FileManager("example.txt","w")asfile, DatabaseConnection("example.db")as connection:...Altyapı:
Bu örnekte, FileManager ve DatabaseConnection context manager'ları aynı with deyimi içinde iç içe kullanılır. Bu sayede dosyayı açıp veritabanı bağlantısını aynı anda kurabiliriz. Takip eden dosya yazma ve veritabanı işlemleri bu birleşik bağlam içinde gerçekleştirilir.
Aklınızda bulundurmanız gereken bir nokta kodun okunabilirliğidir. Aynı anda kullanılan bağlam sayısının ikiyi geçmemesini öneririm.
Sonuç
Python'daki context manager'lar, bir with deyimi içinde kaynak yönetimine yapılandırılmış bir yaklaşım sunarak kaynakların doğru şekilde ayrılmasını ve geri alınmasını sağlar.
Bu eğitim boyunca context manager'ların temellerini öğrendik, pratik örneklerden geçtik ve hata yönetimi ile iç içe kullanım gibi ileri konuları tartıştık. Özel context manager yazmayı öğrenerek daha temiz ve güvenilir kod yazabilir, hata yönetimini iyileştirebilir ve kaynakları verimli şekilde yönetebilirsiniz.
Özel context manager yazma konusu “İleri Düzey Python” başlığının altında yer alır. Becerilerinizi daha da geliştirmek için bazı ilgili kaynaklar şunlardır:
2 yılı aşkın deneyime sahip bir veri bilimi içerik üreticisiyim ve Medium’da en büyük takipçi kitlelerinden birine sahibim. Yapay zekâ ve makine öğrenimi üzerine, biraz da alaycı bir üslupla yazılmış, ayrıntılı makaleler kaleme almayı seviyorum; çünkü onları biraz daha az sıkıcı hale getirmek için bir şeyler yapmak gerekiyor. 130’un üzerinde makale ve bir de DataCamp kursu ürettim; bir diğeri de hazırlık aşamasında. İçeriklerim 5 milyondan fazla kişi tarafından görüldü; bunların 20 bini Medium ve LinkedIn’de takipçim oldu.
Algoritmalar, sistem tasarımı ve davranışsal senaryoları kapsayan bu temel sorularla teknik mülakat sürecine hakim olun. Uzman cevapları, kod örnekleri ve kanıtlanmış hazırlık stratejileri edinin.
Git deponuzu temiz tutmak için .gitignore’u nasıl kullanacağınızı öğrenin. Bu eğitim; temelleri, yaygın kullanım durumlarını ve başlamanıza yardımcı olacak pratik örnekleri kapsar!
Programlama becerilerinizi geliştirin. Kodu nasıl optimize edeceğinizi, fonksiyonları ve testleri nasıl yazacağınızı ve en iyi uygulama yazılım mühendisliği tekniklerini nasıl kullanacağınızı öğrenin.
Motivasyon
withdeyimine, Python'da kaynakları ele almanın özlü bir yoluna, zaten aşina olabilirsiniz. Peki perde arkasında nasıl çalıştığını hiç merak ettiniz mi?withanahtar sözcüğünün gücü context manager'lardan gelir.Context manager'lar, Python'da kaynak yönetimine yapılandırılmış bir yaklaşım sunan temel bir tasarım kalıbıdır. Kaynakların edinilmesini, doğru şekilde kullanılmasını ve hatalar ya da istisnalar olsa bile en sonunda serbest bırakılmasını veya temizlenmesini garanti ederler.
Bu, dosyalar, ağ bağlantıları veya veritabanı tanıtıcıları gibi kaynaklarla çalışırken özellikle önemlidir. Context manager kullanarak, bir dosyayı kapatmayı ya da bir kilidi serbest bırakmayı unutma endişesinden kurtularak daha temiz ve güvenilir kod yazabiliriz.
Bu eğitimde, Python'un varsayılan olarak sunduğu context manager'ların ötesine geçerek kendi context manager'larımızı yazmayı öğreneceğiz.
Python'da Context Manager'ları Anlamak
Perde arkasında, context manager'lar iki özel yöntemi tanımlayan nesnelerdir:
__enter__ve__exit__.__enter__yöntemi, with bloğuna girdiğinizde çağrılır ve dönüş değeri bu blok içindeki bir değişkene atanır. Öte yandan__exit__yöntemi,withbloğu normalde ya da bir istisnayla sona erse de çağrılır.Bu yapı, doğru kaynak yönetimini sağlar. Bunu daha iyi anlamak için Python'daki bazı yerleşik context manager'lara bakalım:
1. Dosya Yönetimi
Klasik bir dosya açma örneğini ele alalım:
Burada,
open('file.txt', 'r')bir context manager olarak davranır.withbloğuna girdiğinizde, dosya nesnesinin enter yöntemi çağrılır, dosya açılır ve file değişkenine atanır. Ardından dosya içeriğine erişmek içinfile.read()kullanabilirsiniz.Sonrasında, dosya nesnesinin
__exit__yöntemi,withbloğu çıkarken bir istisna oluşsa bile mutlaka çağrılır. Bu yöntem, dosyayı kapatmakla ilgilenir; böylece açık dosya tanıtıcıları bırakmamış olursunuz.2. İş Parçacığı Kilitleme
Dosyaların ötesinde, context manager'lar
threading.Lock()kullanılarak iş parçacığı eşzamanlaması için de kullanılabilir:Burada,
lockbirthreading.Locknesnesi, yani başka bir context manager'dır.withbloğuna girdiğinizde__enter__yöntemi kilidi edinir, böylece aynı anda yalnızca bir iş parçacığı kritik bölümü çalıştırabilir. Son olarak,withbloğundan çıkarken__exit__yöntemi kilidi serbest bırakır ve diğer iş parçacıklarının devam etmesine izin verir.3. Veritabanı Bağlantıları
Benzer şekilde, context manager'lar veritabanı bağlantılarını da yönetebilir:
sqlite3.connect('database.db')çağrısı bir context manager'dır.withbloğuna girildiğinde veritabanına bir bağlantı kurulur veconnectiondeğişkenine atanır. Ardından veritabanıyla etkileşim kurmak için bircursorkullanabilirsiniz.withbloğundan çıkarken__exit__yöntemi bağlantının kapatılmasını garanti eder ve kaynak sızıntılarını önler.4. Ağ Soketleri
Context manager'lar ağ iletişimini bile ele alabilir:
Burada,
socket.socket(socket.AF_INET, socket.SOCK_STREAM)bir context manager gibi davranan bir soket nesnesi oluşturur.__enter__yöntemi soketi oluşturur;withbloğu içinde bağlanabilir, veri gönderebilir ve alabilirsiniz.__exit__yöntemi iş bittiğinde soketin düzgün şekilde kapatılmasını sağlar.5. Dizin Taraması
Bu kez,
os.scandir('.')dizin girdileri üzerinde yineleme yapmanın bir yolunu sağlar:Burada
os.scandir('.')context manager olarak davranır.__enter__yöntemi bir dizin taraması açar vewithbloğu içinde girdiler üzerinde yineleme yapabilirsiniz.__exit__yöntemi çıkışta dizin taramasını temizler.Gördüğünüz gibi, context manager'ların gücüyle
withdeyimi, ayırma ve geri alma işlemlerini otomatikleştirerek kaynak yönetimini basitleştirir.Python'da özel context manager yazmak
Şimdi, kaynak yönetimi üzerinde daha ince ayarlı denetim sağlamak için kendi özel manager'larınızı nasıl yazacağınıza bakalım.
Özel context manager yazmanın iki temel yaklaşımı vardır: sınıf tabanlı ve fonksiyon tabanlı.
Sınıf Tabanlı Yaklaşım
Sınıf tabanlı yaklaşım, context manager yazmanın en yapılandırılmış ve esnek yöntemidir. Burada,
__enter__ve__exit__özel yöntemlerini uygulayan bir sınıf tanımlarsınız.Bir çalıştırma süresini ölçen
Timersınıfı örneğine bakalım:Burada,
Timersınıfı, with bloğuna girildiğinde başlangıç zamanını yakalamak için__enter__yöntemini tanımlar. Blok içinde nesneye erişim sağlamak üzereselfdöndürülür.__exit__yöntemi,withbloğundan çıkarken geçen süreyi hesaplar ve yazdırır.Fonksiyon Tabanlı Yaklaşım
Daha kısa ama esneklikten ödün verebilecek bir yaklaşımı tercih ediyorsanız, fonksiyon tabanlı yöntem iyi bir seçenek olabilir. Burada, herhangi bir fonksiyonu bir context manager'a dönüştürmek için
contextlibmodülündekicontextmanagerdekoratörünü kullanırsınız.Bunun nasıl çalıştığına bakalım:
@contextmanagerdekoratörü, timer fonksiyonunu bir context manager'a dönüştürür. Fonksiyon içindestart_timeyakalanır veyieldifadesi yürütmeyi durdurur; böylecewithbloğu içindeki kod çalışır.Son olarak, bitiş zamanı yakalanıp geçen süre yazdırılarak
__exit__işlevselliği sağlanır.Özetle,
__enter__mantığınıyield'dan önce,__exit__mantığını ise sonrasına yazarsınız. Her iki yaklaşım da aynı sonucu elde eder; seçim yapınız yapı ve okunabilirlik tercihlerinize bağlıdır.Context Manager'ların Pratik Örnekleri
Artık Python'da özel context manager yazmayı anladığınıza göre, son derece faydalı olabilecek bazı pratik örneklere bakalım.
Dosya İşlemlerini Yönetmek
Dosya işlemleri birçok uygulamada yaygındır. Dosyalardan okuma ya da dosyalara yazma fark etmeksizin, doğru yönetim veri bütünlüğünü ve kaynak verimliliğini sağlar. Özel bir context manager kullanarak bir dosyaya metin yazmak istediğimiz bir senaryoyu düşünelim.
Bu örnekte, dosya işlemlerini ele alan Python'daki
openişlevini taklit etmek için birFileManagersınıfı tanımlıyoruz. Her yöntemin ne yaptığını parçalayalım:__init__(self, filename, mode): Bu yöntem sınıfın kurucusudur. Açılacak dosyayı ve hangi kipte açılacağını (ör. okuma, yazma, birleştirme) belirten filename ve mode ileFileManagernesnesini başlatır.__enter__(self): Her zamanki gibi,withbloğuna girildiğinde çağrılır.filenameile belirtilen dosyayı,modeile belirtilen kipte açar. Açılan dosya nesnesiself.file'a atanır vewithbloğu içinde kullanılmak üzere döndürülür.__exit__(self, exc_type, exc_value, traceback): Blok içinde bir istisna oluşup oluşmadığına bakılmaksızın, with bloğundan çıkarken çağrılır.self.fileNonedeğilseself.file.close()çağrılarak dosyanın düzgün şekilde kapatılmasını sağlar. Bu, kaynak sızıntılarını engeller ve doğru temizliği garanti eder.Yukarıdaki kodu çalıştırdıktan sonra
example.txtiçeriğini incelerseniz, yazılan metni görmelisiniz:Elbette,
FileManagersınıfının avantajı, dosyalarla çalışmak için istediğiniz özel mantığı uygulayabilmenizdir. Örneğin, açılan veya kapatılan dosyaların bir metin dosyasına kaydını tutacak şekilde sınıfı değiştirebilirsiniz.Bu değiştirilmiş sürümde:
datetimemodülü içe aktarılır.log_actionyöntemi eklenir.log_filenameparametresi eklenir. Varsayılan değer'file_log.txt'olarak ayarlanır.__enter__ve__exit__yöntemleri içindelog_actionkullanılarak dosya adı ve eylem (açıldı ya da kapatıldı) günlük dosyasına eklenir.log_actioniçinde, geçerli zaman damgasını"YYYY-MM-DD HH:MM:SS"biçiminde almak içindatetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")kullanılır.Şimdi,
file_log.txtiçeriğini yazdırırsak, günlükleri görmeliyiz:Özel bir context manager olarak uygulayabileceğimiz bir diğer pratik kullanım durumu da bir SQLite veritabanı yönetim aracıdır:
Bu yine
sqlite3.connectişlevini taklit eder, ancak özel veritabanı yönetim mantığı eklenerek daha da iyileştirilebilir. Yöneticinin çalışıp çalışmadığını bazı örnek işlevlerle kontrol edelim:Veritabanı işlemlerini işlevlere bölerek ve az önce oluşturduğumuz özel yöneticiyi kullanarak çok daha sürdürülebilir kod yazabiliriz.
Python'da Context Manager'larla İlgili İleri Düzey Konular
Bu bölümde, Python'da context manager'larla ilgili ileri düzey konuları ele alacağız. Bunlar arasında hata yönetimi ve iç içe context manager kullanımı yer alır.
Hata yönetimi
Hata yönetimi programlamanın temel bir yönüdür ve Python'daki context manager'lar, kaynak yönetimi işlemleri içinde hataları yönetmek için kullanışlı bir yol sunar.
FileManager sınıfı örneğinde, bir istisna oluşsa bile doğru temizliği sağlamak için
__exit__yönteminin içinde hata yönetimi uygulanabilir. Örneğin, dosyaya veri yazılırken (yaniwithbloğu içindeyken) bir hata oluşursa, kaynak sızıntılarını önlemek için dosyanın yine de kapatılmasını isteriz.__exit__yöntemini şu şekilde değiştirebiliriz:Burada, önce doğru temizliği sağlamak için
self.file.close()ile dosyayı kapatıyoruz. Ardından bir istisna olup olmadığını kontrol ediyoruz(exc_type is not None). Eğer varsa, neyin yanlış gittiğine dair geri bildirim sağlamak için bir hata mesajı yazdırıyoruz.Burada:
exc_type,AttributeErrorveIndexErrorgibi istisna sınıfıdır.exc_value, mesajı içeren istisna örneğidir.traceback, hatanın tam iz bilgisidir.Şimdi, bilerek hatalı bir kodla
FileManagersınıfını çalıştıralım:Dolayısıyla, özel yöneticilerinizde istisnaları ele alırken özel mantık uygulamak için aşağıdaki örnek iş akışını takip edebilirsiniz:
Context manager'ları iç içe kullanmak
Context manager'ları iç içe kullanmak, tek bir
withdeyimi içinde, her biri kendi context manager'ına sahip birden fazla kaynağı aynı anda yönetmenizi sağlar. Bu, birden fazla kaynağı içeren karmaşık işlemlerle uğraşırken özellikle kullanışlıdır. Örneklerimizde context manager'ları nasıl iç içe kullanabileceğimize bakalım.Örneğin, aynı bağlam içinde bir dosya açmak ve veritabanı işlemleri yapmak isteyebiliriz. Belki de bir CSV dosyasının içeriğini satırlar halinde bir veritabanına aktarmak istiyoruz. Bunu tek bir
withdeyimi içindeFileManagerveDatabaseConnectioncontext manager'larını iç içe kullanarak başarabiliriz:Bu örnekte, FileManager ve DatabaseConnection context manager'ları aynı
withdeyimi içinde iç içe kullanılır. Bu sayede dosyayı açıp veritabanı bağlantısını aynı anda kurabiliriz. Takip eden dosya yazma ve veritabanı işlemleri bu birleşik bağlam içinde gerçekleştirilir.Aklınızda bulundurmanız gereken bir nokta kodun okunabilirliğidir. Aynı anda kullanılan bağlam sayısının ikiyi geçmemesini öneririm.
Sonuç
Python'daki context manager'lar, bir
withdeyimi içinde kaynak yönetimine yapılandırılmış bir yaklaşım sunarak kaynakların doğru şekilde ayrılmasını ve geri alınmasını sağlar.Bu eğitim boyunca context manager'ların temellerini öğrendik, pratik örneklerden geçtik ve hata yönetimi ile iç içe kullanım gibi ileri konuları tartıştık. Özel context manager yazmayı öğrenerek daha temiz ve güvenilir kod yazabilir, hata yönetimini iyileştirebilir ve kaynakları verimli şekilde yönetebilirsiniz.
Özel context manager yazma konusu “İleri Düzey Python” başlığının altında yer alır. Becerilerinizi daha da geliştirmek için bazı ilgili kaynaklar şunlardır: