Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Industrial programming >> Python

Python @dekorator properti

Python @dekorator properti

Dalam tutorial ini, Anda akan belajar tentang Python @property decorator; cara pythonic untuk menggunakan getter dan setter dalam pemrograman berorientasi objek.

Pemrograman Python memberi kita @property bawaan dekorator yang membuat penggunaan pengambil dan penyetel lebih mudah dalam Pemrograman Berorientasi Objek.

Sebelum masuk ke detail tentang apa @property dekorator adalah, pertama-tama mari kita membangun intuisi tentang mengapa itu diperlukan.


Kelas Tanpa Getter dan Setter

Mari kita asumsikan bahwa kita memutuskan untuk membuat kelas yang menyimpan suhu dalam derajat Celcius. Itu juga akan menerapkan metode untuk mengubah suhu menjadi derajat Fahrenheit. Salah satu caranya adalah sebagai berikut:

class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

Kita dapat membuat objek dari kelas ini dan memanipulasi temperature atribut sesuai keinginan kita:

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

Keluaran

37
98.60000000000001

Tempat desimal ekstra saat dikonversi ke Fahrenheit adalah karena kesalahan aritmatika floating point. Untuk mempelajari lebih lanjut, kunjungi Python Floating Point Arithmetic Error.

Setiap kali kami menetapkan atau mengambil atribut objek apa pun seperti temperature seperti yang ditunjukkan di atas, Python mencarinya di __dict__ . bawaan objek atribut kamus.

>>> human.__dict__
{'temperature': 37}

Oleh karena itu, man.temperature secara internal menjadi man.__dict__['temperature'] .


Menggunakan Getter dan Setter

Misalkan kita ingin memperluas kegunaan Celsius kelas yang ditentukan di atas. Kita tahu bahwa suhu benda apa pun tidak dapat mencapai di bawah -273,15 derajat Celcius (Nol Mutlak dalam Termodinamika)

Mari perbarui kode kita untuk menerapkan batasan nilai ini.

Solusi yang jelas untuk pembatasan di atas adalah dengan menyembunyikan atribut temperature (jadikan pribadi) dan tentukan metode pengambil dan penyetel baru untuk memanipulasinya. Ini dapat dilakukan sebagai 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 bisa kita lihat, metode di atas memperkenalkan dua get_temperature() baru dan set_temperature() metode.

Selanjutnya, temperature diganti dengan _temperature . Garis bawah _ di awal digunakan untuk menunjukkan variabel pribadi dengan Python.


Sekarang, mari kita gunakan implementasi 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())

Keluaran

37
98.60000000000001
Traceback (most recent call last):
  File "<string>", line 30, in <module>
  File "<string>", line 16, in set_temperature
ValueError: Temperature below -273.15 is not possible.

Pembaruan ini berhasil menerapkan pembatasan baru. Kami tidak lagi diperbolehkan menyetel suhu di bawah -273,15 derajat Celcius.

Catatan :Variabel pribadi sebenarnya tidak ada di Python. Hanya ada norma yang harus diikuti. Bahasa itu sendiri tidak menerapkan batasan apa pun.

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

Namun, masalah yang lebih besar dengan pembaruan di atas adalah bahwa semua program yang mengimplementasikan kelas kami sebelumnya harus mengubah kodenya dari obj.temperature ke obj.get_temperature() dan semua ekspresi seperti obj.temperature = val ke obj.set_temperature(val) .

Pemfaktoran ulang ini dapat menyebabkan masalah saat menangani ratusan ribu baris kode.

Secara keseluruhan, pembaruan baru kami tidak kompatibel ke belakang. Di sinilah @property datang untuk menyelamatkan.


Kelas properti

Cara Pythonic untuk mengatasi masalah di atas adalah dengan menggunakan property kelas. Berikut adalah bagaimana kami dapat memperbarui kode 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 mengamati dengan jelas bahwa mereka sedang dieksekusi.

Baris terakhir kode membuat objek properti temperature . Sederhananya, properti melampirkan beberapa kode (get_temperature dan set_temperature ) ke akses atribut anggota (temperature ).

Mari gunakan kode pembaruan 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

Keluaran

Setting value...
Getting value...
37
Getting value...
98.60000000000001
Setting value...
Traceback (most recent call last):
  File "<string>", line 31, in <module>
  File "<string>", line 18, in set_temperature
ValueError: Temperature below -273 is not possible

Seperti yang kita lihat, kode apa pun yang mengambil nilai temperature akan secara otomatis memanggil get_temperature() alih-alih pencarian kamus (__dict__). Demikian pula, kode apa pun yang memberikan nilai ke temperature akan secara otomatis memanggil set_temperature() .

Kita bahkan dapat melihat di atas bahwa set_temperature() dipanggil bahkan saat kita membuat objek.

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

Dapatkah Anda menebak alasannya?

Alasannya adalah ketika sebuah objek dibuat, __init__() metode dipanggil. Metode ini memiliki baris self.temperature = temperature . Ekspresi ini secara otomatis memanggil set_temperature() .

Demikian pula, akses apa pun seperti c.temperature secara otomatis memanggil get_temperature() . Inilah yang dilakukan properti. 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 ada modifikasi yang diperlukan dalam penerapan batasan nilai. Dengan demikian, implementasi kami kompatibel ke belakang.

Catatan :Nilai suhu aktual disimpan di _temperature private pribadi variabel. temperature atribut adalah objek properti yang menyediakan antarmuka ke variabel pribadi ini.


Dekorator @properti

Dengan Python, property() adalah fungsi bawaan yang membuat dan mengembalikan property obyek. Sintaks dari fungsi ini adalah:

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

dimana,

Dilihat dari implementasinya, argumen fungsi ini bersifat opsional. Jadi, objek properti cukup dibuat sebagai berikut.

>>> property()
<property object at 0x0000000003239B38>

Objek properti memiliki tiga metode, getter() , setter() , dan deleter() untuk menentukan fget , fset dan fdel di kemudian hari. Artinya, baris:

temperature = property(get_temperature,set_temperature)

dapat dipecah menjadi:

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

Kedua potongan kode ini setara.

Pemrogram yang akrab dengan Dekorator Python dapat mengenali bahwa konstruksi di atas dapat diimplementasikan sebagai dekorator.

Kami bahkan tidak dapat menentukan nama get_temperature dan set_temperature karena tidak diperlukan dan mencemari namespace kelas.

Untuk ini, kami menggunakan kembali temperature name sambil mendefinisikan fungsi pengambil dan penyetel kami. Mari kita lihat bagaimana menerapkan ini sebagai dekorator:

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

Keluaran

Setting value...
Getting value...
37
Getting value...
98.60000000000001
Setting value...
Traceback (most recent call last):
  File "", line 29, in 
  File "", line 4, in __init__
  File "", line 18, in temperature
ValueError: Temperature below -273 is not possible

Implementasi di atas sederhana dan efisien. Ini adalah cara yang disarankan untuk menggunakan property .


Python

  1. Tipe Data Python
  2. Operator Python
  3. Pernyataan lulus python
  4. Argumen Fungsi Python
  5. Kamus Python
  6. Warisan Python
  7. Kelebihan Operator Python
  8. Python Iterator
  9. Penutupan Python
  10. Python @dekorator properti