Bu bölümde "decorator" kavramından yüzeysel olarak bahsedeceğiz. Bu decorator kavramının tam olarak ne iş yaptığını, ileriki bloglarda öğreneceğiz. Decorator yapıları genel olarak, bir class içerisinde özel bir özelliği dinamik olarak değiştirmemize olanak tanıyor ve bunu, diğer özellikleri bozmadan yapıyor. Decorator yapıları '@' işareti ile tanımlanırlar. Örneğin geçtiğimiz bölümlerde gördüğümüz @classmethod, @staticmethod gibi yapılar da aslında birer Decorator örneğidir. Bu bölümde 2 önemli Decorator ifadesini öğrenmeye çalışacağız.
Öncelikle Keyboard adında, klavyeleri baz alan bir class yaratalım ve içerisine name, numpad ve price olmak üzere 3 özellik ekleyelim.

İki adet nesne de oluşturdum ve içlerine hep string ifadeler verdim. Normalde False - True ve 400 - 300 ifadeleri sırasıyla bool ve int tipindeler ama fazla uzatmamak adına bu şekilde tanımladım.
6. satıra dikkat ederseniz __init__ içerisinde olmayan bir özellik daha tanımladığımı görürsünüz. Burada self.filter ifadesi, klavyedeki numpad özelliği ile o klavyenin fiyatına (price) eşit; bir nevi filtreleme yaptık diyebiliriz.
Şimdi, k1 nesnesinin filter özelliğine erişmeyi denersek karşımıza şöyle bir sonuç çıkacaktır: False 400, öyle değil mi? Buraya kadar her şey normal. Peki, diyelim ki fiyat bilgisi güncellendi ve artık 400 TL değil, 420 TL olmalı. Bu durumda filter özelliği değişir mi?

k1.price = "420" dedikten sonra normalde bunun değişmiş olması lazım. Ancak k1.filter dediğimiz zaman bunun değişmediğini, tabiri caizse self.filter = self.numpad + " " + self.price kodunun bir kalıp hâline dönüştüğünü görüyoruz.
Aslında filter özelliği __init__ içerisinde bulunmadığı için o tek bir defa atanıyor ve duruyor. Sonrasında yapılan değişiklikler ile bu özelliğin değerleri de değişmiyor. Ancak k1.price = "420" dediğimizde aslında price değeri değişiyor. Bakalım.

price değeri değişmesine rağmen filter değeri değişmedi; hâlbuki filter özelliğinin içinde price özelliği de mevcuttu. Dediğim gibi; bir kalıp hâline dönüştü çünkü bunu __init__'e verip dinamik olarak nesnelerle eşleşmesini sağlamadık.
Bu, ilk bakışta çok önemli bir sorun olarak görünmeyebilir ama kodunuzun büyüklüğü göz önüne alındığında bu sorun, doğru orantılı bir şekilde büyüyecektir. Peki, filter özelliğini __init__'e vermeyi düşünebiliriz ama o zaman ona, az önce yaptığımız gibi bir filtre atamak zorlaşır.
Dolayısıyla bunu bir metot olarak yazmak işimize yarayacaktır, deneyelim.

Aynı tanımlamayı filterKeyboards(self): metoduna koydum ve return self.filter dedim. Artık bir metodumuz var ve dinamik olarak güncelleniyor.
Dikkat ederseniz bu bir metot olduğu için bunu çalıştırırken () ifadesini kullanıyoruz. Bu durum, şu an için problemi ortadan kaldırmış gibi görünse de projenin büyümesi ile beraber çeşitli sorunlar ortaya çıkacaktır. Bu sorunların kesişim noktası ise, Keyboard sınıfına bağlı olan başka sınıflar olacaktır. Bu tarz bir değişiklikte bahsettiğim bu 'başka sınıflara' gidip hepsinde benzer bir düzeltmeyi yapmanız gerekir.
Bunun önüne geçebilmek adına metot olarak duran bu ifadeyi bir özellikmiş gibi gösterebiliriz. İşte tam olarak bu noktada devreye @property decorator yapısı giriyor. "Property" kelimesinin anlamı "özellik" şeklindedir. Hemen nasıl yapıldığına bakalım.

Oluşturduğumuz metodun hemen üstündeki satıra gidip @property derseniz bu metot artık bir özellik gibi işlev görecektir. Aşağı tarafa dikkat ederseniz biraz önce k1.filterKeyboards() yaparken şimdi k1.filterKeyboards yaptık. Yani parantezleri yazmadık. Bu kullanımı, normal özellikler için yapıyorduk ve @property sayesinde bunu, bir metot üzerinde uygulayabildik.
Oldukça güzel. Ancak burada da ufak bir problemimiz olabilir. Hemen ne olduğunu beraber inceleyelim.

k1 nesnesinin filter özelliğini k1.filterKeyboards = "True 500" şeklinde değiştirmek istediğimde bana AttributeError yani özellik hatası veriyor. Diyor ki: "Özellik tanımlanamadı (set)". İşte, bunun sebebi aslında @property'nin yaptığı görünürde özellikten kaynaklıdır. Yani @property, filterKeyboards isimli metodu bir özellikmiş gibi gösterdi ama aslında arka planda o hâlâ bir metot.
Bu sorunu aşmak için bir diğer Decorator yapımız olan @setter ifadesini kullanacağız. Zaten genel olarak @property ile @setter Decorator yapıları birlikte kullanılır. Nasıl kullanıldığını görelim.

Biraz karmaşık göründüğünün farkındayım ama sakin olalım. Bu dekoratörü tanımlarken @ işaretinden sonra bir metot referans vermeniz gerekir. Bu metot, @property ile özellik olarak gösterilen bir metot olmalıdır. Örneğin biz filterKeyboards(self) şeklinde bir @property metodu tanımladık ve bu metot artık bir özellik oldu. @filterKeyboards.setter derken de bu değişkeni tam olarak atama işlemini gerçekleştiriyoruz.
Metodun içerisine girdiğimde numpad, price = toBeFiltered.split(" ") dedim. Sonrasında __init__ içerisindeymişim gibi self.numpad = numpad ve self.price = price dedim. Bu sayede True ve 500 ifadeleri birbirinden ayrılarak ait oldukları yerlere gideceklerdir. Yani numpad = "True" ve price = "500" olarak k1 nesnesinin özellikleri güncellenecektir.
Dikkat ederseniz biraz önce k1.filterKeyboards = "True 500" dediğimde AttributeError almıştım. Şimdi ise aynı kullanımı yapmama rağmen bir sorunla karşılaşmadım. İşte, bunun sebebi, @setter Decorator yapısıdır.
Yayınlanma Tarihi: 2022-12-28 18:19:19
Son Düzenleme Tarihi: 2022-12-31 13:45:13