2.23. Dekoratörler

Dekoratör, bir fonksiyonu (veya bir yöntemi) başka bir fonksiyonla saran bir söz dizimi parçasıdır. Sarmalayıcı, orijinal çağrıdan önce ve sonra davranış ekleyebilir, dönüş değerini değiştirebilir veya meta veri ekleyebilir. Biçimi şöyledir:

@wrapper
def f():
    ...

@wrapper satırı f = wrapper(f) ifadesine eşdeğerdir – f fonksiyonu normal şekilde oluşturulur, ardından wrapper‘a verilir ve sonuç f adına yeniden bağlanır.

Soldan bir "wrapper" kutusuna giren ve sağdan dekore edilmiş bir fonksiyon olarak çıkan bir fonksiyon.

Bir dekoratör bir fonksiyon alır ve yeni bir fonksiyon döndürür.

2.23.1. Yerleşik yöntem dekoratörleri

Python ile birlikte gelen ve sınıf gövdeleri içinde kullanılan birkaç dekoratör vardır.

2.23.1.1. @property

Bir yöntemi hesaplanmış bir niteliğe dönüştürür. Çağıran, sanki düz bir nitelikmiş gibi ona erişir (parantez yok), ancak her okumada bir yöntem çalışır:

class Circle:
    def __init__(self, radius):
        self.radius = radius

    @property
    def area(self):
        return 3.14159 * self.radius * self.radius

c = Circle(5)
print(c.area)             # 78.53975  -- no parentheses

Bunu, basit görünen bir niteliğin arkasında küçük bir hesaplama gerektiğinde kullanın. İş pahalıysa, normal bir yöntemi tercih edin – çağıranlar nitelik okumalarının yavaş olmasını beklemez.

2.23.1.2. @classmethod

Bir örnek yerine ilk argümanı olarak sınıfı alan bir yöntem tanımlar. İlk parametre geleneksel olarak cls olarak adlandırılır:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @classmethod
    def origin(cls):
        return cls(0, 0)

p = Point.origin()

Sınıf yöntemleri, alternatif kurucular sağlamanın standart yoludur – varsayılan olmayan bir şekilde oluşturulmuş bir örnek döndüren fabrika fonksiyonları.

2.23.1.3. @staticmethod

Ne örneği ne de sınıfı alan bir yöntem tanımlar – bu, yalnızca düzenleme nedenleriyle sınıf ad alanında yaşayan düz bir fonksiyondur:

class Temperature:
    @staticmethod
    def c_to_f(c):
        return c * 9 / 5 + 32

Temperature.c_to_f(100)   # 212.0

Bunu idareli kullanın; bir fonksiyonun gerçekten sınıfın durumuyla hiçbir ilgisi yoksa, düz bir modül düzeyinde fonksiyon genellikle daha temizdir.

2.23.2. Özel bir dekoratör yazmak

Dekoratör, bir fonksiyon alıp bir fonksiyon döndüren bir fonksiyondur. Minimum biçim:

def log_calls(func):
    def wrapper(*args, **kwargs):
        print("calling", func.__name__)
        return func(*args, **kwargs)
    return wrapper

@log_calls
def add(a, b):
    return a + b

add(2, 3)

Çıktı:

calling add

wrapper, func üzerinde kapanış oluşturur ve her şeyi ona iletir. *args / **kwargs, yalnızca iki argümanlı olanlar için değil, herhangi bir fonksiyon üzerinde çalışmasını sağlar. Bu kalıp, daha ayrıntılı dekoratörlerin (zamanlama, önbellekleme, başarısızlıkta yeniden deneme) temelidir ancak özü her zaman aynıdır: bir fonksiyon al, bir fonksiyon döndür.