Python @property: Bagaimana Menggunakannya dan Mengapa? - Programiz

Dalam tutorial ini, anda akan belajar mengenai Python @property decorator; kaedah pythonic untuk menggunakan getter dan setter dalam pengaturcaraan berorientasikan objek.

Pengaturcaraan Python menyediakan kita dengan @propertypenghias terbina dalam yang menjadikan penggunaan getter dan setter lebih mudah dalam Pengaturcaraan Berorientasikan Objek.

Sebelum membahas mengenai apa itu @propertypenghias, marilah kita terlebih dahulu membina intuisi tentang mengapa ia diperlukan terlebih dahulu.

Kelas Tanpa Pemula dan Pengawal

Mari kita anggap bahawa kita memutuskan untuk membuat kelas yang menyimpan suhu dalam darjah Celsius. Ini juga akan menerapkan metode untuk mengubah suhu menjadi derajat Fahrenheit. Salah satu cara untuk melakukan ini adalah seperti berikut:

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

Kita boleh membuat objek dari kelas ini dan memanipulasi temperatureatribut seperti yang kita mahukan:

 # 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())

Pengeluaran

 37 98.60000000000001

Tempat perpuluhan tambahan ketika menukar menjadi Fahrenheit adalah disebabkan oleh kesalahan aritmetik titik terapung. Untuk mengetahui lebih lanjut, lawati Ralat Aritmetik Titik Terapung Python.

Setiap kali kita menetapkan atau mengambil atribut objek seperti yang temperatureditunjukkan di atas, Python mencarinya di __dict__atribut kamus bawaan objek .

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

Oleh itu, secara man.temperaturedalaman menjadi man.__dict__('temperature').

Menggunakan Getter dan Setter

Andaikan kita ingin memperluaskan kebolehgunaan kelas Celsius yang dinyatakan di atas. Kita tahu bahawa suhu objek tidak boleh mencapai di bawah -273.15 darjah Celsius (Zero Mutlak dalam Termodinamik)

Mari kemas kini kod kami untuk melaksanakan kekangan nilai ini.

Penyelesaian yang jelas untuk sekatan di atas adalah menyembunyikan atribut temperature(menjadikannya peribadi) dan menentukan kaedah mendapatkan dan menetapkan baru untuk memanipulasinya. Ini boleh dilakukan seperti berikut:

 # 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

Seperti yang dapat kita lihat, kaedah di atas memperkenalkan dua kaedah get_temperature()dan set_temperature()kaedah baru .

Selanjutnya, temperaturedigantikan dengan _temperature. Garis bawah _pada awalnya digunakan untuk menunjukkan pemboleh ubah peribadi di Python.

Sekarang, mari kita gunakan pelaksanaan ini:

 # 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())

Pengeluaran

 37 98.60000000000001 Jejak Balik (panggilan terakhir terakhir): Fail "", baris 30, dalam Fail "", baris 16, dalam set_temperature ValueError: Suhu di bawah -273.15 tidak mungkin.

Kemas kini ini berjaya melaksanakan sekatan baru. Kami tidak lagi dibenarkan menetapkan suhu di bawah -273.15 darjah Celsius.

Catatan : Pemboleh ubah peribadi sebenarnya tidak wujud di Python. Terdapat beberapa norma yang harus diikuti. Bahasa itu sendiri tidak menerapkan sekatan.

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

Walau bagaimanapun, masalah yang lebih besar dengan maklumat di atas adalah bahawa semua program yang dilaksanakan kelas kami sebelum ini perlu mengubah suai kod mereka dari obj.temperaturekepada obj.get_temperature()dan ungkapan seperti obj.temperature = valuntuk obj.set_temperature(val).

Pemfaktoran semula ini boleh menyebabkan masalah semasa berurusan dengan ratusan ribu baris kod.

Secara keseluruhan, kemas kini baru kami tidak serasi ke belakang. Di sinilah tempat @propertyuntuk menyelamatkan.

Kelas harta tanah

Kaedah pythonic untuk mengatasi masalah di atas adalah dengan menggunakan propertykelas. Inilah cara kami mengemas kini kod kami:

 # 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)

Kami menambahkan print()fungsi di dalam get_temperature()dan set_temperature()untuk melihat dengan jelas bahawa mereka sedang dijalankan.

Baris terakhir kod membuat objek harta benda temperature. Ringkasnya, properti melampirkan beberapa kod ( get_temperaturedan set_temperature) pada atribut anggota yang mengakses ( temperature).

Mari gunakan kod kemas kini ini:

 # 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

Pengeluaran

 Menetapkan nilai … Mendapatkan nilai … 37 Mendapatkan nilai … 98.60000000000001 Menetapkan nilai … Jejak (panggilan terakhir terakhir): Fail "", baris 31, dalam Fail "", baris 18, dalam nilai set_temperatureError: Suhu di bawah -273 tidak mungkin

Seperti yang kita lihat, sebarang kod yang mengambil nilai temperatureakan memanggil secara automatik get_temperature()dan bukannya mencari kamus (__dict__). Begitu juga, mana-mana kod yang memberikan nilai temperatureakan dipanggil secara automatik set_temperature().

Kita bahkan dapat melihat di atas yang set_temperature()dipanggil walaupun kita membuat objek.

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

Bolehkah anda meneka mengapa?

Sebabnya ialah apabila objek dibuat, __init__()kaedah dipanggil. Kaedah ini mempunyai garis self.temperature = temperature. Ungkapan ini secara automatik memanggil set_temperature().

Begitu juga, akses seperti c.temperaturepanggilan secara automatik get_temperature(). Inilah yang dilakukan oleh harta benda. Berikut adalah beberapa contoh lagi.

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

Dengan menggunakan property, kita dapat melihat bahwa tidak diperlukan modifikasi dalam pelaksanaan batasan nilai. Oleh itu, pelaksanaan kami serasi ke belakang.

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)

Kedua-dua kod ini setara.

Pengaturcara yang biasa dengan Python Decorators dapat menyedari bahawa konstruk di atas dapat dilaksanakan sebagai penghias.

Kami bahkan tidak dapat menentukan nama get_temperaturedan set_temperaturekerana nama itu tidak perlu dan mencemarkan ruang nama kelas.

Untuk ini, kami menggunakan semula temperaturenama sambil menentukan fungsi getter dan setter kami. Mari lihat bagaimana melaksanakannya sebagai penghias:

 # 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)

Pengeluaran

 Menetapkan nilai … Mendapatkan nilai … 37 Mendapatkan nilai … 98.60000000000001 Menetapkan nilai … Jejak (panggilan terakhir terakhir): Fail "", baris 29, dalam Fail "", baris 4, dalam __init__ File "", baris 18, dalam suhu ValueError: Suhu di bawah -273 tidak mungkin

Pelaksanaan di atas adalah mudah dan cekap. Ini adalah cara penggunaan yang disyorkan property.

Artikel menarik...