Merhaba;
Şu an üzerinde çalıştığım projede (ve genel olarak) hataları yakalama ve düzenli olarak loglama ihtiyacı hissettim, elbette try-except blokları ile bu yapıyı sağlayabilsem de, bir yerden sonra kodun hemen her parçasını try-except yapısına boğduğumu ve bu yapının da kodun okunaklığına ve akışına zarar verdiğini gördüm. Biraz araştırma yapınca, bu kontrol sistemi için güzel bir yapının olduğunu gördüm. Öncelikle fonksiyon deseni hakkında genel bir bilgiye sahip olmak gerekli bu yapıyı kullanabilmek için, bunun için araştırdıklarım arasında en güzel anlatım şu kaynakta
mevcuttu;
http://thecodeship.com/patterns/guide-to-python-function-decorators/
Özetle, fonksiyon deseni, aslında bildiğimiz dekoratör deseninin fonksiyonlara uyarlanmış versiyonudur. Yani dekoratör deseninde sınıfları implemente(Türkçesi saçma olduğu için mecburen ingilizcesini Türkçeleştirmişcesine kullandım kusura bakmayın) ederken, manipülasyon için kullanırken, fonksiyon deseninde de, direk fonksiyonları bir başka fonksiyondan üzerinden çağırarak kontrol ve manipülasyon işini bu fonksiyon üzerinden yapıyoruz. Bu sayede hata durumlarını burada filtreleyerek loglayabiliyoruz. Yapı olarak wrapper’lara benzemektedir. Python’u burada işlevsel kılan ise functool’dur. Functool altındaki wraps sayesinde, içerisine gönderdiğimiz fonksiyonun kimlik bilgilerini kaybetmeden, fonksiyon işlemlerini yapabilme yetisine sahip oluyoruz.
Hadi bunu biraz kod ile açıklayalım,
# Author: Sezer Yavuzer Bozkir <admin@sezerbozkir.com>
# Created Date: 03.05.2017
# Website: sezerbozkir.com
from functools import wraps
def tags(tag_name):
def tags_decorator(func):
@wraps(func) # Fonksiyonun özelliklerini aktarmayı sağlayan wrapper
def func_wrapper(name):
return "<{0}>{1}</{0}>".format(tag_name, func(name)) # Fonksiyonun manipülasyonu
return func_wrapper
return tags_decorator
@tags("p")
def get_text(name):
"""İçeriğe dair detaylar"""
return "Hello " + name
print(get_text.__name__) # get_text
print(get_text.__doc__) # returns some text
print(get_text.__module__) # __main__
print(get_text("ornek"))
Kodu çalıştırdığınızda, şöyle bir çıktı elde etmekteyiz;
Şimdi gelelim bunu hata yakalama işlevi için nasıl kullanacağımıza. Az-çok mantığını kestirebildiğinizi düşünüyorum. Yakaladığım hataları yazmak için logging kütüphanesinden faydalanıyorum (istek olursa bir gün onu da anlatırım pek tabii);
# Author: Sezer Yavuzer Bozkir <admin@sezerbozkir.com>
# License: REIDIN Commercial
# Created Date: 03.05.2017
# Version:
# Website: sezerbozkir.com
import functools
import logging
def create_logger():
"""
Logger oluşturup, döndurecek fonksiyon
"""
logger = logging.getLogger("ornek_logger")
logger.setLevel(logging.INFO)
# Logun kaydedileceği dosyayı belirt, burada path de kullanılabilir orn: /var/log/ornek.log
fh = logging.FileHandler("hata_kaydedici.log")
fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
formatter = logging.Formatter(fmt)
fh.setFormatter(formatter)
# Hata yakalayıca formatı ekle
logger.addHandler(fh)
return logger
def exception(function):
"""
A decorator that wraps the passed in function and logs
exceptions should one occur
Olası Hataları yakalayıp loglayacak fonksiyon
"""
@functools.wraps(function)
def wrapper(*args, **kwargs):
logger = create_logger()
try:
return function(*args, **kwargs)
except:
# Hatayı logla
err = "There was an exception in "
err += function.__name__
logger.exception(err)
# (isteğe bağlı) hatayı tekrar fırlat
raise
return wrapper
Artık hangi fonksiyonu bu filtreye dahil edecek isek, başına @exception eklememiz yeterli olacaktır.
Örnek kullanımı;
# Author: Sezer Yavuzer Bozkir <admin@sezerbozkir.com>
# Created Date: 03.05.2017
# Website: sezerbozkir.com
from error_handler import exception
@exception
def sifira_bolunme_denemesi():
1 / 0
if __name__ == '__main__':
sifira_bolunme_denemesi()
Log kaydı;
Umarım faydalı olabilmişimdir.
Data detaylı bilgi için kaynak


