Menu
Coddy logo textTech

Sınıf Dekoratörleri

Coddy'nin Python Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 40 / 64.

Sınıf dekoratörleri, sınıfları başka bir fonksiyonla sarmalayarak değiştirmenize veya geliştirmenize olanak tanır. Fonksiyon dekoratörleri gibi çalışırlar ancak tüm sınıflara uygulanırlar.

İşte dekoratör içermeyen basit bir sınıf:

class Person:
    def __init__(self, name):
        self.name = name
        
    def greet(self):
        return f"Hello, my name is {self.name}"

Yeni bir metot ekleyen bir sınıf dekoratörü (class decorator) oluşturun:

def add_farewell(cls):
    def farewell(self):
        return f"Goodbye from {self.name}"
    
    cls.farewell = farewell  # Metodu sınıfa ekle
    return cls

Dekoratörü bir sınıfa @ kullanarak uygulayın:

@add_farewell
class EnhancedPerson:
    def __init__(self, name):
        self.name = name
        
    def greet(self):
        return f"Hello, my name is {self.name}"

Artık sınıf hem orijinal hem de eklenen metotlara sahip:

person = EnhancedPerson("Alice")
print(person.greet())     # Merhaba, benim adım Alice
print(person.farewell())  # Alice'den elveda

Ayrıca, mevcut bir metodu sarmalayabilirsiniz — orijinalini saklayarak sarmalayıcı içinde hala çağırabilmenizi sağlar. Bu, sınıfın halihazırda sahip olduğu bir metodun etrafına davranış (izleme veya günlük kaydı gibi) eklemek istediğinizde kullanışlıdır:

def add_tracking(cls):
    original_greet = cls.greet  # Orijinal metodu sakla

    def tracked_greet(self):
        print(f"greet was called")   # Öncesinde ekstra davranış
        return original_greet(self)  # Orijinal metodu çağır

    cls.greet = tracked_greet  # Sınıftaki metodu değiştir
    return cls

@add_tracking
class TrackedPerson:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Hello, my name is {self.name}"

Şimdi greet fonksiyonunu çağırdığınızda, önce sarmalayıcı çalışır, ardından orijinal fonksiyona devreder:

person = TrackedPerson("Alice")
print(person.greet())
# greet çağrıldı
# Hello, my name is Alice

Mevcut bir metodu sarmalamak için temel adımlar şunlardır:
1. Orijinal metodu kaydedin: original = cls.method
2. original(self) çağrısını ve ek mantığı içeren yeni bir fonksiyon tanımlayın.
3. Yeni fonksiyonu sınıfa geri atayın: cls.method = new_function
4. Değiştirilmiş sınıfı döndürün.

Önemli Nokta: Sınıf dekoratörleri girdi olarak bir sınıf alır, onu değiştirir veya geliştirir ve değiştirilmiş sınıfı döndürür. Metotlar ekleyebilir, öznitelikleri değiştirebilir veya mevcut işlevselliği sarmalayabilirler. Bunları uygulamak için sınıf tanımının üzerinde @decorator_name kullanın. Bu, kalıtım kullanmadan sınıf işlevselliğini genişletmek için temiz bir yol sağlar.

challenge icon

Görev

Orta

Bu meydan okumada, metot çağrısı izleme özelliği ekleyen bir sınıf dekoratörü uygulayacaksınız.

  • decorator.py - add_counter sınıf dekoratörünü uygulayın
  • calculator.py - Dekoratörünüzü kullanacak sınıfları içerir

driver.py dosyası, uygulamanızı çeşitli kullanım durumlarına, kalıtım modellerine ve uç durumlara karşı doğrulayacak kapsamlı test senaryoları içerir. Bu dosyayı değiştirmenize gerek yoktur, ancak dosyayı incelemek beklenen davranışı anlamanıza yardımcı olacaktır.

Kopya kağıdı

Sınıf dekoratörleri (class decorators), sınıfları başka bir fonksiyonla sarmalayarak onları değiştirir veya geliştirir. Girdi olarak bir sınıf alırlar, onu değiştirirler ve değiştirilmiş sınıfı geri döndürürler.

Temel sınıf dekoratörü sözdizimi:

def decorator_name(cls):
    # Modify the class
    return cls

@decorator_name
class MyClass:
    pass

Örnek - bir sınıfa metot ekleme:

def add_farewell(cls):
    def farewell(self):
        return f"Goodbye from {self.name}"
    
    cls.farewell = farewell  # Add the method to the class
    return cls

@add_farewell
class EnhancedPerson:
    def __init__(self, name):
        self.name = name
        
    def greet(self):
        return f"Hello, my name is {self.name}"

person = EnhancedPerson("Alice")
print(person.greet())     # Hello, my name is Alice
print(person.farewell())  # Goodbye from Alice

Örnek - mevcut bir metodu sarmalama (orijinali sakla, sonra değiştir):

def loud_greet(cls):
    original_greet = cls.greet  # Store the original method

    def new_greet(self):
        result = original_greet(self)  # Call the original
        return result.upper()          # Enhance the result

    cls.greet = new_greet  # Replace with the wrapped version
    return cls

@loud_greet
class EnhancedPerson:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Hello, my name is {self.name}"

person = EnhancedPerson("Alice")
print(person.greet())  # HELLO, MY NAME IS ALICE

Mevcut bir metodu sarmalamak için temel adımlar:

original = cls.method_name — orijinal metodu kaydet
def new_method(self): original(self) — sarmalayıcı içinde onu çağır
cls.method_name = new_method — sınıftaki metodu yenisiyle değiştir

Sınıf dekoratörleri, kalıtım (inheritance) kullanmadan metot ekleyebilir, öznitelikleri değiştirebilir veya mevcut işlevselliği sarmalayabilir.

Kendin dene

from calculator import Calculator

# Kapsamlı test senaryosu işleyicisi
test_case = input()

if test_case == "basic_functionality":
    calc = Calculator()
    print(calc.add(5, 3))  # 8 yazdırmalı
    print(calc.add(2, 7))  # 9 yazdırmalı
    print(calc.subtract(10, 4))  # 6 yazdırmalı
    print(calc.call_counts)  # {'add': 2, 'subtract': 1} yazdırmalı

elif test_case == "multiple_instances":
    calc1 = Calculator()
    calc2 = Calculator()
    
    print(calc1.add(5, 3))  # 8 yazdırmalı
    print(calc2.add(2, 7))  # 9 yazdırmalı
    print(calc1.subtract(10, 4))  # 6 yazdırmalı
    
    # Her iki örnek de aynı call_counts değerini paylaşmalı
    print(calc1.call_counts)  # {'add': 2, 'subtract': 1} yazdırmalı
    print(calc2.call_counts)  # {'add': 2, 'subtract': 1} yazdırmalı
    print(calc1.call_counts is calc2.call_counts)  # True yazdırmalı

elif test_case == "method_call_order":
    calc = Calculator()
    
    print(calc.add(1, 2))  # 3 yazdırmalı
    print(calc.subtract(5, 2))  # 3 yazdırmalı
    print(calc.add(10, 20))  # 30 yazdırmalı
    print(calc.add(7, 3))  # 10 yazdırmalı
    print(calc.call_counts)  # {'add': 3, 'subtract': 1} yazdırmalı

elif test_case == "large_values":
    calc = Calculator()
    
    print(calc.add(1000000, 2000000))  # 3000000 yazdırmalı
    print(calc.subtract(5000000, 2000000))  # 3000000 yazdırmalı
    print(calc.call_counts)  # {'add': 1, 'subtract': 1} yazdırmalı

elif test_case == "negative_values":
    calc = Calculator()
    
    print(calc.add(-5, -3))  # -8 yazdırmalı
    print(calc.subtract(-10, -4))  # -6 yazdırmalı
    print(calc.call_counts)  # {'add': 1, 'subtract': 1} yazdırmalı

elif test_case == "float_values":
    calc = Calculator()
    
    print(calc.add(5.5, 3.2))  # 8.7 yazdırmalı
    print(calc.subtract(10.5, 4.2))  # 6.3 yazdırmalı
    print(calc.call_counts)  # {'add': 1, 'subtract': 1} yazdırmalı

elif test_case == "zero_values":
    calc = Calculator()
    
    print(calc.add(0, 0))  # 0 yazdırmalı
    print(calc.subtract(0, 0))  # 0 yazdırmalı
    print(calc.call_counts)  # {'add': 1, 'subtract': 1} yazdırmalı

elif test_case == "counter_reset":
    calc = Calculator()
    
    print(calc.add(5, 3))  # 8 yazdırmalı
    print(calc.call_counts)  # {'add': 1, 'subtract': 0} yazdırmalı
    
    # Sayacı sıfırla
    calc.call_counts = {"add": 0, "subtract": 0}
    
    print(calc.add(2, 7))  # 9 yazdırmalı
    print(calc.call_counts)  # {'add': 0, 'subtract': 0} yazdırmalı

elif test_case == "counter_manipulation":
    calc = Calculator()
    
    print(calc.add(5, 3))  # 8 yazdırmalı
    print(calc.call_counts)  # {'add': 1, 'subtract': 0} yazdırmalı
    
    # Sayacı doğrudan manipüle et
    calc.call_counts["add"] = 100
    
    print(calc.add(2, 7))  # 9 yazdırmalı
    print(calc.call_counts)  # {'add': 101, 'subtract': 0} yazdırmalı

elif test_case == "performance_test":
    calc = Calculator()
    
    # 1000 toplama işlemi gerçekleştir
    for i in range(1000):
        calc.add(i, i+1)
    
    # 500 çıkarma işlemi gerçekleştir
    for i in range(500):
        calc.subtract(i+10, i)
    
    print(calc.call_counts)  # {'add': 1000, 'subtract': 500} yazdırmalı
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Object Oriented Programming bölümündeki tüm dersler