Python @property: Nasıl Kullanılır ve Neden? - Programlama

Bu eğitimde, Python @property decorator; nesne yönelimli programlamada alıcıları ve ayarlayıcıları kullanmanın pitonik bir yolu.

Python programlama bize @property, Nesne Tabanlı Programlamada alıcı ve ayarlayıcıların kullanımını çok daha kolaylaştıran yerleşik bir dekoratör sağlar.

@propertyDekoratörün ne olduğuna dair ayrıntılara girmeden önce , ilk olarak neden ilk etapta gerekli olacağına dair bir sezgi oluşturalım.

Getters ve Setters Olmadan Sınıf

Sıcaklığı Santigrat derece olarak depolayan bir sınıf yapmaya karar verdiğimizi varsayalım. Ayrıca, sıcaklığı Fahrenheit derecelerine dönüştürmek için bir yöntem uygular. Bunu yapmanın bir yolu şudur:

 class Celsius: def __init__(self, temperature = 0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32

Bu sınıftan nesneler yapabilir ve temperatureözniteliği istediğimiz gibi değiştirebiliriz :

 # Basic method of setting and getting attributes in Python class Celsius: def __init__(self, temperature=0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 # Create a new object human = Celsius() # Set the temperature human.temperature = 37 # Get the temperature attribute print(human.temperature) # Get the to_fahrenheit method print(human.to_fahrenheit())

Çıktı

 37 98.60000000000001

Fahrenheit'e dönüştürürken fazladan ondalık basamaklar, kayan nokta aritmetik hatasından kaynaklanır. Daha fazla bilgi edinmek için Python Kayan Nokta Aritmetik Hatası sayfasını ziyaret edin.

temperatureYukarıda gösterildiği gibi herhangi bir nesne niteliğini atadığımızda veya aldığımızda , Python onu nesnenin yerleşik __dict__sözlük özniteliğinde arar .

 >>> human.__dict__ ('temperature': 37)

Bu nedenle, man.temperaturedahili olarak olur man.__dict__('temperature').

Getiricileri ve Ayarlayıcıları Kullanma

Yukarıda tanımlanan Celsius sınıfının kullanılabilirliğini genişletmek istediğimizi varsayalım. Herhangi bir cismin sıcaklığının -273,15 santigrat derecenin (Termodinamikte Mutlak Sıfır) altına ulaşamayacağını biliyoruz.

Bu değer kısıtlamasını uygulamak için kodumuzu güncelleyelim.

Yukarıdaki kısıtlamanın bariz bir çözümü, niteliği gizlemek temperature(özel yapmak) ve onu işlemek için yeni alıcı ve ayarlayıcı yöntemleri tanımlamak olacaktır. Bu şöyle yapılabilir:

 # Making Getters and Setter methods class Celsius: def __init__(self, temperature=0): self.set_temperature(temperature) def to_fahrenheit(self): return (self.get_temperature() * 1.8) + 32 # getter method def get_temperature(self): return self._temperature # setter method def set_temperature(self, value): if value < -273.15: raise ValueError("Temperature below -273.15 is not possible.") self._temperature = value

Gördüğümüz gibi, yukarıdaki yöntem iki yeni get_temperature()ve yöntem ortaya koymaktadır set_temperature().

Ayrıca, temperatureile değiştirildi _temperature. _Python'da özel değişkenleri belirtmek için başında bir alt çizgi kullanılır.

Şimdi bu uygulamayı kullanalım:

 # Making Getters and Setter methods class Celsius: def __init__(self, temperature=0): self.set_temperature(temperature) def to_fahrenheit(self): return (self.get_temperature() * 1.8) + 32 # getter method def get_temperature(self): return self._temperature # setter method def set_temperature(self, value): if value < -273.15: raise ValueError("Temperature below -273.15 is not possible.") self._temperature = value # Create a new object, set_temperature() internally called by __init__ human = Celsius(37) # Get the temperature attribute via a getter print(human.get_temperature()) # Get the to_fahrenheit method, get_temperature() called by the method itself print(human.to_fahrenheit()) # new constraint implementation human.set_temperature(-300) # Get the to_fahreheit method print(human.to_fahrenheit())

Çıktı

 37 98.60000000000001 Geri izleme (en son çağrı): Dosya "", satır 30, Dosya "", satır 16, set_temperature ValueError: -273.15'in altında sıcaklık mümkün değildir.

Bu güncelleme yeni kısıtlamayı başarıyla uyguladı. Artık sıcaklığı -273,15 santigrat derecenin altına ayarlamamıza izin verilmiyor.

Not : Özel değişkenler aslında Python'da mevcut değildir. İzlenecek basit normlar var. Dilin kendisi herhangi bir kısıtlama uygulamaz.

 >>> human._temperature = -300 >>> human.get_temperature() -300

Bununla birlikte, yukarıdaki güncellemeyle ilgili daha büyük sorun, önceki sınıfımızı uygulayan tüm programların kodlarını 'den' obj.temperaturee obj.get_temperature()ve tüm ifadelerin hoşlandığı gibi obj.temperature = valdeğiştirmek zorunda olmasıdır obj.set_temperature(val).

Bu yeniden düzenleme, yüz binlerce satır kodla uğraşırken sorunlara neden olabilir.

Sonuç olarak, yeni güncellememiz geriye dönük olarak uyumlu değildi. Burası @propertykurtarmaya geliyor.

Mülk Sınıfı

Yukarıdaki problemle başa çıkmanın pitonik bir yolu propertysınıfı kullanmaktır . Kodumuzu şu şekilde güncelleyebiliriz:

 # using property class class Celsius: def __init__(self, temperature=0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 # getter def get_temperature(self): print("Getting value… ") return self._temperature # setter def set_temperature(self, value): print("Setting value… ") if value < -273.15: raise ValueError("Temperature below -273.15 is not possible") self._temperature = value # creating a property object temperature = property(get_temperature, set_temperature)

print()İçeriye bir fonksiyon ekledik get_temperature()ve set_temperature()bunların yürütüldüğünü açıkça gözlemledik.

Kodun son satırı bir özellik nesnesi oluşturur temperature. Basitçe ifade etmek gerekirse, özellik , üye özniteliği erişimlerine ( ) bazı kod ( get_temperatureve set_temperature) ekler temperature.

Bu güncelleme kodunu kullanalım:

 # using property class class Celsius: def __init__(self, temperature=0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 # getter def get_temperature(self): print("Getting value… ") return self._temperature # setter def set_temperature(self, value): print("Setting value… ") if value < -273.15: raise ValueError("Temperature below -273.15 is not possible") self._temperature = value # creating a property object temperature = property(get_temperature, set_temperature) human = Celsius(37) print(human.temperature) print(human.to_fahrenheit()) human.temperature = -300

Çıktı

 Değer ayarı… Değer alınıyor… 37 Değer alınıyor… 98.60000000000001 Değer ayarı… Geri izleme (en son çağrı son): Dosya "", satır 31, Dosya "", satır 18, set_temperature ValueError: -273'ün altında sıcaklık mümkün değil

Gördüğümüz gibi, değerini alan herhangi bir kod, sözlük (__dict__) temperaturearaması get_temperature()yerine otomatik olarak çağıracaktır . Benzer şekilde, bir değer atayan herhangi bir kod temperatureotomatik olarak çağırır set_temperature().

Hatta yukarıda set_temperature()bir nesne oluşturduğumuzda çağrıldığını görebiliriz .

 >>> human = Celsius(37) Setting value… 

Nedenini tahmin edebilir misin?

Bunun nedeni, bir nesne oluşturulduğunda __init__()yöntemin çağrılmasıdır. Bu yöntemin çizgisi var self.temperature = temperature. Bu ifade otomatik olarak çağırır set_temperature().

Benzer şekilde, c.temperatureotomatik arama gibi herhangi bir erişim get_temperature(). Mülkiyetin yaptığı budur. İşte birkaç örnek daha.

 >>> human.temperature Getting value 37 >>> human.temperature = 37 Setting value >>> c.to_fahrenheit() Getting value 98.60000000000001

Kullanarak property, değer kısıtlamasının uygulanmasında herhangi bir değişikliğe gerek olmadığını görebiliriz. Dolayısıyla uygulamamız geriye dönük uyumludur.

Note: The actual temperature value is stored in the private _temperature variable. The temperature attribute is a property object which provides an interface to this private variable.

The @property Decorator

In Python, property() is a built-in function that creates and returns a property object. The syntax of this function is:

 property(fget=None, fset=None, fdel=None, doc=None)

where,

  • fget is function to get value of the attribute
  • fset is function to set value of the attribute
  • fdel is function to delete the attribute
  • doc is a string (like a comment)

As seen from the implementation, these function arguments are optional. So, a property object can simply be created as follows.

 >>> property() 

A property object has three methods, getter(), setter(), and deleter() to specify fget, fset and fdel at a later point. This means, the line:

 temperature = property(get_temperature,set_temperature)

can be broken down as:

 # make empty property temperature = property() # assign fget temperature = temperature.getter(get_temperature) # assign fset temperature = temperature.setter(set_temperature)

Bu iki kod parçası eşdeğerdir.

Python Dekoratörlerine aşina programcılar, yukarıdaki yapının dekoratörler olarak uygulanabileceğini fark edebilir.

Biz bile isimlerini tanımlayamazsınız get_temperatureve set_temperatureonlar gereksiz gibi sınıf ad alanını kirletmektedir.

Bunun için temperaturealıcı ve ayarlayıcı işlevlerimizi tanımlarken adı yeniden kullanıyoruz . Bunu bir dekoratör olarak nasıl uygulayacağımıza bakalım:

 # Using @property decorator class Celsius: def __init__(self, temperature=0): self.temperature = temperature def to_fahrenheit(self): return (self.temperature * 1.8) + 32 @property def temperature(self): print("Getting value… ") return self._temperature @temperature.setter def temperature(self, value): print("Setting value… ") if value < -273.15: raise ValueError("Temperature below -273 is not possible") self._temperature = value # create an object human = Celsius(37) print(human.temperature) print(human.to_fahrenheit()) coldest_thing = Celsius(-300)

Çıktı

 Değer ayarlanıyor… Değer alınıyor… 37 Değer alınıyor… 98.60000000000001 Değer ayarı… Geri izleme (en son çağrı son): Dosya "", satır 29, Dosya "", satır 4, __init__ Dosyasında "", satır 18, sıcaklık Değer Hatası: -273'ün altındaki sıcaklık mümkün değildir

Yukarıdaki uygulama basit ve etkilidir. Tavsiye edilen kullanım şeklidir property.

Ilginç makaleler...