Menu
CoddyTech

Decorator Class

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Python di Coddy. Pelajaran 40 dari 64.

Dekorator class memungkinkan kamu mengubah atau meningkatkan class dengan membungkusnya menggunakan fungsi lain. Cara kerjanya seperti dekorator fungsi, tetapi diterapkan pada seluruh class.

Berikut class sederhana tanpa dekorasi:

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

Buat dekorator class yang menambahkan method baru:

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

Terapkan decorator ke class menggunakan @:

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

Sekarang class ini memiliki method asli dan method tambahan:

person = EnhancedPerson("Alice")
print(person.greet())     # Halo, nama saya Alice
print(person.farewell())  # Salam perpisahan dari Alice

Kamu juga bisa membungkus method yang sudah ada: menyimpan method aslinya agar kamu tetap bisa memanggilnya di dalam pembungkus. Ini berguna saat kamu ingin menambahkan perilaku (seperti pelacakan atau pencatatan) di sekitar method yang sudah dimiliki class:

def add_tracking(cls):
    original_greet = cls.greet  # Simpan method asli

    def tracked_greet(self):
        print(f"greet was called")   # Jalankan perilaku tambahan sebelumnya
        return original_greet(self)  # Panggil method asli

    cls.greet = tracked_greet  # Ganti method pada class
    return cls

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

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

Saat kamu memanggil greet sekarang, wrapper dijalankan terlebih dahulu, lalu meneruskan ke fungsi aslinya:

person = TrackedPerson("Alice")
print(person.greet())
# greet dipanggil
# Halo, nama saya Alice

Langkah-langkah utama untuk membungkus method yang sudah ada adalah:
1. Simpan method asli: original = cls.method
2. Definisikan fungsi baru yang memanggil original(self) beserta logika tambahan apa pun.
3. Tetapkan kembali fungsi baru ke class: cls.method = new_function
4. Kembalikan class yang telah dimodifikasi.

Poin penting: Decorator class menerima class sebagai input, memodifikasi atau meningkatkannya, lalu mengembalikan class yang telah dimodifikasi. Decorator class dapat menambahkan method, memodifikasi atribut, atau membungkus fungsionalitas yang sudah ada. Gunakan @decorator_name di atas definisi class untuk menerapkannya. Cara ini memberikan pendekatan yang rapi untuk memperluas fungsionalitas class tanpa pewarisan.

challenge icon

Tantangan

Sedang

Dalam tantangan ini, kamu akan menerapkan decorator class yang menambahkan fungsi pelacakan pemanggilan method.

  • decorator.py - Terapkan decorator class add_counter
  • calculator.py - Berisi class yang akan menggunakan decoratormu

File driver.py berisi banyak skenario pengujian yang akan memvalidasi penerapanmu dengan berbagai kasus penggunaan, pola pewarisan, dan kasus tepi. Kamu tidak perlu mengubah file ini, tetapi memeriksanya akan membantumu memahami perilaku yang diharapkan.

Coba sendiri

from calculator import Calculator

# Penangan kasus uji yang menyeluruh
test_case = input()

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

elif test_case == "multiple_instances":
    calc1 = Calculator()
    calc2 = Calculator()
    
    print(calc1.add(5, 3))  # Seharusnya mencetak 8
    print(calc2.add(2, 7))  # Seharusnya mencetak 9
    print(calc1.subtract(10, 4))  # Seharusnya mencetak 6
    
    # Kedua instance seharusnya berbagi call_counts yang sama
    print(calc1.call_counts)  # Seharusnya mencetak {'add': 2, 'subtract': 1}
    print(calc2.call_counts)  # Seharusnya mencetak {'add': 2, 'subtract': 1}
    print(calc1.call_counts is calc2.call_counts)  # Seharusnya mencetak True

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

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

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

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

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

elif test_case == "counter_reset":
    calc = Calculator()
    
    print(calc.add(5, 3))  # Seharusnya mencetak 8
    print(calc.call_counts)  # Seharusnya mencetak {'add': 1, 'subtract': 0}
    
    # Atur ulang penghitung
    calc.call_counts = {"add": 0, "subtract": 0}
    
    print(calc.add(2, 7))  # Seharusnya mencetak 9
    print(calc.call_counts)  # Seharusnya mencetak {'add': 0, 'subtract': 0}

elif test_case == "counter_manipulation":
    calc = Calculator()
    
    print(calc.add(5, 3))  # Seharusnya mencetak 8
    print(calc.call_counts)  # Seharusnya mencetak {'add': 1, 'subtract': 0}
    
    # Ubah penghitung secara langsung
    calc.call_counts["add"] = 100
    
    print(calc.add(2, 7))  # Seharusnya mencetak 9
    print(calc.call_counts)  # Seharusnya mencetak {'add': 101, 'subtract': 0}

elif test_case == "performance_test":
    calc = Calculator()
    
    # Lakukan 1000 operasi add
    for i in range(1000):
        calc.add(i, i+1)
    
    # Lakukan 500 operasi subtract
    for i in range(500):
        calc.subtract(i+10, i)
    
    print(calc.call_counts)  # Seharusnya mencetak {'add': 1000, 'subtract': 500}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Python online