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 @property
penghias terbina dalam yang menjadikan penggunaan getter dan setter lebih mudah dalam Pengaturcaraan Berorientasikan Objek.
Sebelum membahas mengenai apa itu @property
penghias, 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 temperature
atribut 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 temperature
ditunjukkan di atas, Python mencarinya di __dict__
atribut kamus bawaan objek .
>>> human.__dict__ ('temperature': 37)
Oleh itu, secara man.temperature
dalaman 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, temperature
digantikan 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.temperature
kepada obj.get_temperature()
dan ungkapan seperti obj.temperature = val
untuk 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 @property
untuk menyelamatkan.
Kelas harta tanah
Kaedah pythonic untuk mengatasi masalah di atas adalah dengan menggunakan property
kelas. 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_temperature
dan 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 temperature
akan memanggil secara automatik get_temperature()
dan bukannya mencari kamus (__dict__). Begitu juga, mana-mana kod yang memberikan nilai temperature
akan 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.temperature
panggilan 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 attributefset
is function to set value of the attributefdel
is function to delete the attributedoc
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_temperature
dan set_temperature
kerana nama itu tidak perlu dan mencemarkan ruang nama kelas.
Untuk ini, kami menggunakan semula temperature
nama 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
.