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.

A function entering a "wrapper" box on the left and emerging on the right as a decorated function.

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.