İleri Düzey Programcılar İçin Python Dekoratörlerine Yönelik Bir Kılavuz

Python dekoratörleri, fonksiyonların veya yöntemlerin davranışlarını değiştirmek için güçlü ve esnek bir araçtır. Programcıların çağrılabilir nesnelerin işlevselliğini temiz, okunabilir ve sürdürülebilir bir şekilde genişletmesine veya değiştirmesine olanak tanır. Bu makale, iç içe dekoratörler, dekoratör argümanları ve sınıf tabanlı dekoratörler dahil olmak üzere Python dekoratörleriyle ilgili gelişmiş kavramları inceler.

Dekoratörler Nelerdir?

Dekoratörler, başka bir fonksiyonun davranışını değiştiren fonksiyonlardır. Başka bir fonksiyonu, kodunu açıkça değiştirmeden davranışını genişletmek için sararlar. Dekoratörler, @decorator_name sözdizimini kullanarak tanımlanır ve fonksiyon tanımının üstüne yerleştirilir.

Temel Dekoratör Sözdizimi

Basit bir süsleyici, bir fonksiyonu argüman olarak alır, bir miktar davranış ekleyen bir iç fonksiyon tanımlar ve sonra iç fonksiyonu döndürür.

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

Argümanlı Dekoratör Fonksiyonları

Dekoratörler argümanları kabul ederek daha esnek olabilir. Böyle bir dekoratör oluşturmak için, bir dekoratör döndüren bir fonksiyon yazmanız gerekir. Bu, dekoratörlere daha dinamik davranış eklemeyi sağlar.

def repeat(num_times):
    def decorator_repeat(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator_repeat

@repeat(num_times=3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Yuvalama Dekoratörleri

Dekoratörler, birden fazla davranışı birleştirmek için iç içe yerleştirilebilir. Örneğin, tek bir fonksiyonda iki veya daha fazla dekoratör kullanabiliriz.

def uppercase_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

def repeat_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result + result
    return wrapper

@repeat_decorator
@uppercase_decorator
def say_word(word):
    return word

print(say_word("hello"))

Sınıf Tabanlı Dekoratörler

Python'da, dekoratörler __call__ metodu kullanılarak sınıflar olarak da uygulanabilir. Sınıf tabanlı dekoratörler, daha karmaşık durum yönetimi ve davranışa ihtiyaç duyduğunuzda kullanışlıdır.

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print(f"Call {self.num_calls} of {self.func.__name__!r}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()
say_hello()

Meta Verileri Korumak için functools.wraps Kullanımı

Dekoratörler yazdığınızda, dekore edilmiş fonksiyon orijinal meta verilerini, örneğin adını ve doküman dizisini kaybeder. functools.wraps dekoratörü, orijinal fonksiyonun meta verilerini sarmalayıcı fonksiyona kopyalamak için kullanılabilir.

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Wrapper function executed before", func.__name__)
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def display_info(name, age):
    """Displays name and age."""
    print(f"display_info ran with arguments ({name}, {age})")

print(display_info.__name__)  # Output: display_info
print(display_info.__doc__)   # Output: Displays name and age.

Çözüm

Python dekoratörleri, esnek kod tasarımı ve davranış değişikliğine olanak tanıyan güçlü bir özelliktir. İç içe dekoratörler, argümanlı dekoratörler ve sınıf tabanlı dekoratörler gibi gelişmiş kullanımlar, Python programlarına daha fazla işlevsellik ve okunabilirlik sağlayabilir. Dekoratörleri doğru bir şekilde anlayarak ve kullanarak, geliştiriciler daha özlü, verimli ve okunabilir kod yazabilirler.