Menu
Coddy logo textTech

İleri Seviye Property Dekoratörleri

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

Gelişmiş özellik dekoratörleri; hesaplanmış özellikler, silici metotlar ve tam özellik yönetimi dahil olmak üzere öznitelik erişimi üzerinde daha gelişmiş kontrol sağlar.

İşte diğer özniteliklerden değerler türeten hesaplanmış özelliklere (computed properties) bir örnek:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    @property
    def area(self):
        return self.width * self.height
    
    @property
    def perimeter(self):
        return 2 * (self.width + self.height)

Hesaplanmış özellikleri normal öznitelikler gibi kullanın:

rect = Rectangle(5, 3)
print(rect.area)      # 15 - otomatik olarak hesaplandı
print(rect.perimeter) # 16 - otomatik olarak hesaplandı

Getter (alıcı), setter (ayarlayıcı) ve deleter (silici) özelliklerine sahip bir özellik (property) oluşturun:

class Temperature:
    def __init__(self):
        self._temp = 0
    
    @property
    def temperature(self):
        return self._temp
    
    @temperature.setter
    def temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below absolute zero!")
        self._temp = value
    
    @temperature.deleter
    def temperature(self):
        print("Resetting temperature to 0")
        self._temp = 0

Tam özellik işlevselliğini kullanın:

temp = Temperature()

Doğrulama içeren ayarlayıcıyı (setter) kullanın:

temp.temperature = 25
print(temp.temperature)  # 25

# temp.temperature = -300  # ValueError hatası fırlatır

Siliciyi kullanın:

del temp.temperature
print(temp.temperature)  # 0

Bir oyun puanı ile daha karmaşık bir örnek oluşturalım:

class Player:
    def __init__(self, name):
        self.name = name
        self._score = 0
        self._level = 1
    
    @property
    def score(self):
        return self._score
    
    @score.setter
    def score(self, value):
        if value >= 0:
            self._score = value
            self._level = (value // 1000) + 1
        else:
            raise ValueError("Score cannot be negative")
    
    @score.deleter
    def score(self):
        print(f"Resetting {self.name}'s progress")
        self._score = 0
        self._level = 1
    
    @property
    def level(self):
        return self._level

player = Player("Alice")
player.score = 2500
print(f"Score: {player.score}, Level: {player.level}")  # Score: 2500, Level: 3

del player.score
print(f"Score: {player.score}, Level: {player.level}")  # Score: 0, Level: 1

Çıktı:

15
16
25
Resetting temperature to 0
0
Score: 2500, Level: 3
Resetting Alice's progress
Score: 0, Level: 1

Anahtar Nokta: Gelişmiş özellik dekoratörleri (property decorators); hesaplanmış özelliklere (diğer verilerden hesaplanan), @property.deleter ile özellik silmeye ve öznitelikleri alma, ayarlama ve silme üzerinde tam kontrole olanak tanır. Bu, güçlü veri doğrulama ve kapsüllemeyi (encapsulation) korurken sezgisel arayüzler oluşturur.

challenge icon

Görev

Orta

Bu challenge'da, uygun kapsülleme (encapsulation) ve özellik doğrulaması (property validation) içeren bir Rectangle sınıfı uygulayacaksınız.

  • rectangle.py - Düzenlemeniz gereken dosyadır, uygulamanıza rehberlik edecek TODO yorumlarını içerir
  • driver.py - Kapsamlı test senaryolarını içerir (değiştirmeyin)
  1. _width ve _height için özel (private) öznitelikler uygulayın
  2. Doğrulama içeren (pozitif olmalı) width ve height özellikleri oluşturun
    • TODO'larda belirtilen uygun ValueError mesajlarını fırlatın
    • Önemli: Değerin 0'a eşit veya daha küçük olup olmadığını kontrol edin, ardından hatayı fırlatın (bu, tutarlı bir davranış sağlar)
  3. area ve perimeter için salt okunur (read-only) özellikler uygulayın
  4. TODO'larda açıklandığı gibi getter, setter ve deleter işlevselliğine sahip bir dimensions özelliği oluşturun
    • Önemli: Setter içinde demet açma (tuple unpacking) sözdizimini kullanın: width, height = dimensions

Kopya kağıdı

Gelişmiş özellik dekoratörleri (property decorators), hesaplanmış özellikler, siliciler (deleters) ve tam özellik yönetimi ile öznitelik erişimi üzerinde gelişmiş kontrol sağlar.

Hesaplanmış Özellikler:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    @property
    def area(self):
        return self.width * self.height
    
    @property
    def perimeter(self):
        return 2 * (self.width + self.height)

Getter, Setter ve Deleter ile Tam Özellik:

class Temperature:
    def __init__(self):
        self._temp = 0
    
    @property
    def temperature(self):
        return self._temp
    
    @temperature.setter
    def temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below absolute zero!")
        self._temp = value
    
    @temperature.deleter
    def temperature(self):
        print("Resetting temperature to 0")
        self._temp = 0

Kullanım:

# Hesaplanmış özellikler
rect = Rectangle(5, 3)
print(rect.area)      # 15
print(rect.perimeter) # 16

# Tam özellik işlevselliği
temp = Temperature()
temp.temperature = 25  # Setter kullanır
print(temp.temperature)  # Getter kullanır

del temp.temperature   # Deleter kullanır

Kendin dene

from rectangle import Rectangle

# Test durumu işleyicisi
test_case = input()

# Temel işlevsellik testi
if test_case == "default_test":
    rect = Rectangle(5, 3)
    print(f"Width: {rect.width}, Height: {rect.height}")
    print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")
    
    # Boyutlar (dimensions) özelliğini test et
    print(f"Dimensions: {rect.dimensions}")
    rect.dimensions = (10, 8)
    print(f"New area: {rect.area}")
    
    # Doğrulamayı test et
    try:
        rect.width = -2
    except ValueError as e:
        print(f"Validation error: {e}")
    
    # Siliciyi (deleter) test et
    del rect.dimensions
    print(f"After reset: {rect.dimensions}")

# Sıfır değerleri ile test
elif test_case == "zero_values":
    try:
        rect = Rectangle(0, 5)
    except ValueError as e:
        print(f"Error creating rectangle: {e}")
    
    try:
        rect = Rectangle(5, 0)
    except ValueError as e:
        print(f"Error creating rectangle: {e}")

# Negatif değerler ile test
elif test_case == "negative_values":
    rect = Rectangle(5, 3)
    original_dimensions = rect.dimensions
    
    try:
        rect.dimensions = (5, -3)
    except ValueError as e:
        print(f"Error setting dimensions: {e}")
    
    print(f"Dimensions after failed update: {rect.dimensions}")
    print(f"Original dimensions preserved: {rect.dimensions == original_dimensions}")

# Büyük değerler ile test
elif test_case == "large_values":
    rect = Rectangle(1000000, 2000000)
    print(f"Large rectangle area: {rect.area}")
    print(f"Large rectangle perimeter: {rect.perimeter}")

# Ondalıklı (float) değerler ile test
elif test_case == "float_values":
    rect = Rectangle(3.5, 2.75)
    print(f"Dimensions: {rect.dimensions}")
    print(f"Area: {rect.area}")
    print(f"Perimeter: {rect.perimeter}")
    
    rect.dimensions = (1.1, 2.2)
    print(f"New area with float dimensions: {rect.area}")

# Tip hataları ile test
elif test_case == "type_errors":
    try:
        rect = Rectangle("5", 3)
    except Exception as e:
        print(f"Type error during creation: {type(e).__name__}: {e}")
    
    rect = Rectangle(5, 3)
    try:
        rect.dimensions = 10  # Bir demet (tuple) değil
    except Exception as e:
        print(f"Type error setting dimensions: {type(e).__name__}: {e}")

# Çoklu özellik işlemleri testi
elif test_case == "property_operations":
    rect = Rectangle(5, 10)
    print(f"Initial - Width: {rect.width}, Height: {rect.height}, Area: {rect.area}")
    
    rect.width = 8
    print(f"After width change - Width: {rect.width}, Area: {rect.area}")
    
    rect.height = 6
    print(f"After height change - Height: {rect.height}, Area: {rect.area}")
    
    rect.dimensions = (12, 9)
    print(f"After dimensions change - Dimensions: {rect.dimensions}, Area: {rect.area}")
    
    del rect.dimensions
    print(f"After reset - Dimensions: {rect.dimensions}, Area: {rect.area}")

# Özellik doğrulama sınır durumları testi
elif test_case == "validation_edge_cases":
    rect = Rectangle(5, 3)
    
    try:
        rect.width = 0
    except ValueError as e:
        print(f"Zero width error: {e}")
    
    # Çok küçük pozitif değer kabul edilmelidir
    rect.height = 0.0001
    print(f"Small height accepted: {rect.height}")
    print(f"Area with small height: {rect.area}")

# Çoklu dikdörtgen testi
elif test_case == "multiple_rectangles":
    rect1 = Rectangle(5, 3)
    rect2 = Rectangle(10, 2)
    rect3 = Rectangle(4, 4)
    
    print(f"Rectangle 1 - Area: {rect1.area}, Perimeter: {rect1.perimeter}")
    print(f"Rectangle 2 - Area: {rect2.area}, Perimeter: {rect2.perimeter}")
    print(f"Rectangle 3 - Area: {rect3.area}, Perimeter: {rect3.perimeter}")
    
    # Her bir dikdörtgeni değiştir
    rect1.width = 7
    rect2.height = 5
    rect3.dimensions = (6, 6)
    
    print(f"After modifications:")
    print(f"Rectangle 1 - Dimensions: {rect1.dimensions}")
    print(f"Rectangle 2 - Dimensions: {rect2.dimensions}")
    print(f"Rectangle 3 - Dimensions: {rect3.dimensions}")

# Birçok işlem ile performans testi
elif test_case == "performance_test":
    rect = Rectangle(5, 5)
    
    # Birçok özellik işlemi gerçekleştir
    for i in range(1000):
        rect.width = i % 10 + 1  # 1-10 arası değerler
        rect.height = i % 5 + 1  # 1-5 arası değerler
        area = rect.area  # Hesaplanmış özelliğe eriş
        perimeter = rect.perimeter  # Hesaplanmış özelliğe eriş
        dims = rect.dimensions  # Özellik alıcısına (getter) eriş
    
    print(f"Final state after 1000 operations:")
    print(f"Width: {rect.width}, Height: {rect.height}")
    print(f"Area: {rect.area}, Perimeter: {rect.perimeter}")
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