koddla

Yazılımcıları bilgi ile güçlendirir.

Python’da getter ve setter fonksiyonları nasıl kullanılır?

Programlama dillerinde mutator yöntemi bir değişkendeki değişiklikleri kontrol etmek için kullanılan bir yöntemdir. Genel olarak getter/setter yöntemleri olarak da bilinirler.

Mutator yöntemi en sık kapsülleme ilkesine uygun olarak nesne yönelimli programlamada kullanılır. Bu ilkeye göre, bir sınıfın üye değişkenleri, bunları gizlemek ve diğer kodlardan korumak için özel hale getirilirler. Dolayısıyla yalnızca istenen yeni değeri parametre olarak alan, isteğe bağlı olarak doğrulayan ve bu değişkeni değiştiren bir fonksiyon (mutator yöntemi) tarafından değiştirilebilirler.

Başka bir programla dilinden Python’a geçtiyseniz getter/setter tanımlamak için aşağıdakine benzer bir yöntem kullanıyor olabilirsiniz:

def set_property(property,value):  
def get_property(property):  

Ancak Pythonda bu sevilmez. Mutator kullanmanın “Pythonic” yolu “getters” ve “setters” kullanmak değildir. Bunun aksine python özelliklerini (property) kullanırız.

value adında bir değişkenimiz olsun. Bu değişkenin değerine aşağıdaki gibi ulaşırız:

value = 'something'

obj.attribute = value  #set
value = obj.attribute  #get
del obj.attribute         #del

Sonrasında bu değerleri değiştirmek veya almak için ise property dekoratörünü kullanarak kullanıcı kodunu değiştirmek zorunda kalmadan değere ulaşabiliriz.

class Obj:
    """property demo"""
    #
    @property            # getter metodu
    def attribute(self): # getter metodu değişken ismi ile aynı
        return self._attribute
    #
    @attribute.setter    # .setter dekoratörü
    def attribute(self, value):   # fonksiyon ismi aynı
        self._attribute = value   # value değişkenine eşitledik
    #
    @attribute.deleter     # silmek için .deleter dekoratörü
    def attribute(self):   # metod adı yine aynı
        del self._attribute

(Her dekoratör kullanımı önceki özellik nesnesini kopyalar ve güncelleştirir, bu nedenle her getter/setter ve silme işlemi için aynın isimde işlev/yöntem kullanmanız gerektiğini unutmayın.)

Yukarıdakileri tanımladıktan sonra koddan erişimimiz ilk başta yazdığımız gibi olacak:

obj = Obj()
obj.attribute = value  
the_value = obj.attribute
del obj.attribute

Tekrar başa dönelim ve ilk başta düşündüğümüz getter/setter metotlarımıza bakalım.

def set_property(property,value):  
def get_property(property):  

Öncelikle, yukarıdakiler çalışmayacaktır. Çünkü değerin eşitleneceğini belirteceğimiz bağımsız bir değişken sağlamıyoruz – bu genellikle self ile tanımlanır.

class Obj:

    def set_property(self, property, value): 
        ...
    def get_property(self, property):        
        ...

İkincisi, bu kullanım tarzı __setattr__ ve __getattr__ yöntemlerinin sadece fazladan bir kopyasını oluşturuyor.

Üçüncü olarak, pythonda yerleşik setattr ve getattr fonksiyonlarına sahibiz.

setattr(object, 'property_name', value)
getattr(object, 'property_name', default_value)  

@property dekoratörü, getters ve setterler yaratmak içindir.

Öte yandan değerlerin erişimini kısıtlamak için fonksiyonun davranışını değiştirebiliriz:

class Protective(object):

    @property
    def protected_value(self):
        return self._protected_value

    @protected_value.setter
    def protected_value(self, value):
        if acceptable(value): # e.g. type or range check
            self._protected_value = value

Sonuç olarak, doğrudan öznitelikleri kullanmaktan kaçınmak ve sadece property kullanmak isteriz.

Diğer Python kullanıcıları tarafından da beklenen budur. “En az sürpriz” kuralına uyarız. Zorlayıcı bir nedeniniz olmadıkça kodunuzu okuyacak kişilere beklediklerini vermeye çalışmalısınız.

Örnek

Örneğin, nesnemizin korumalı özniteliğinin 0 ile 100 (dahil) arasında bir tamsayı olmasını isteyelim. Kullanıcıya da bu kuralların uygun kullanımı hakkında bilgilendireceğimiz mesajlarımız olsun. Ayrıca özelliğin silinmesini de önlemek isteyelim:

class Protective(object):
    """protected property demo"""
    #
    def __init__(self, start_protected_value=0):
        self.protected_value = start_protected_value
    # 
    @property
    def protected_value(self):
        return self._protected_value
    #
    @protected_value.setter
    def protected_value(self, value):
        if value != int(value):
            raise TypeError("protected_value must be an integer")
        if 0 <= value <= 100:
            self._protected_value = int(value)
        else:
            raise ValueError("protected_value must be " +
                             "between 0 and 100 inclusive")
    #
    @protected_value.deleter
    def protected_value(self):
        raise AttributeError("do not delete, protected_value can be set to 0")

Kullanıma bakalım:

>>> p1 = Protective(3)
>>> p1.protected_value
3
>>> p1 = Protective(5.0)
>>> p1.protected_value
5
>>> p2 = Protective(-5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
  File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> p1.protected_value = 7.3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 17, in protected_value
TypeError: protected_value must be an integer
>>> p1.protected_value = 101
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> del p1.protected_value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 18, in protected_value
AttributeError: do not delete, protected_value can be set to 0

İsimlerin önemi var mı?

Evet, var. .setter ve .deleter orijinal özelliğin kopyalarını yapar. Bu, alt sınıfların üstteki davranışı değiştirmeden kendi davranışını düzgün bir şekilde değiştirmesine olanak tanır.

class Obj:
    """property demo"""
    #
    @property
    def get_only(self):
        return self._attribute
    #
    @get_only.setter
    def get_or_set(self, value):
        self._attribute = value
    #
    @get_or_set.deleter
    def get_set_or_delete(self):
        del self._attribute

Şimdi ilgili adları kullanmanız gerekir:

obj = Obj()
# obj.get_only = 'value' # would error
obj.get_or_set = 'value'  
obj.get_set_or_delete = 'new value'
the_value = obj.get_only
del obj.get_set_or_delete
# del obj.get_or_set # would error

Son

Basit özelliklerle başlayın. Daha sonra get, set ve silme işlevlerine ihtiyacınız varsa dekoratör aracılığı ile bunları ekleyin. Bunu yaparken get_ veya set_ isimli işlevleri kullanmaktan kaçını.

Bir yanıt yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Back to top