Python @property: Kuinka sitä käytetään ja miksi? - Programiz

Tässä opetusohjelmassa opit Python @property decoratorista; pythoninen tapa käyttää hautoja ja asettimia olio-ohjelmoinnissa.

Python-ohjelmointi tarjoaa meille sisäänrakennetun @propertysisustajan, joka helpottaa getterin ja setereiden käyttöä olio-ohjelmoinnissa.

Ennen kuin ryhdymme yksityiskohtiin siitä, mitä @propertysisustaja on, rakentakaamme ensin intuitio siitä, miksi sitä tarvitsisi ensiksi.

Luokka ilman getereitä ja settereitä

Oletetaan, että päätämme tehdä luokan, joka tallentaa lämpötilan celsiusasteina. Se ottaisi käyttöön myös menetelmän lämpötilan muuntamiseksi Fahrenheit-asteiksi. Yksi tapa tehdä tämä on seuraava:

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

Voimme tehdä esineitä tästä luokasta ja muokata temperaturemääritettä haluamallamme tavalla:

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

Tuotos

 37 98.60000000000001

Fahrenheitiksi muunnettaessa ylimääräiset desimaaliluvut johtuvat liukuluvun aritmeettisesta virheestä. Lisätietoja on osoitteessa Python Floating Point Arithmetic Error.

Aina kun osoitamme tai haemme objektimääritettä, kuten temperatureyllä on esitetty, Python etsii sitä objektin sisäänrakennetusta __dict__sanakirjamääritteestä.

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

Siksi man.temperaturesisäisesti tulee man.__dict__('temperature').

Getters- ja Setters-sovellusten käyttäminen

Oletetaan, että haluamme laajentaa edellä määritellyn Celsius-luokan käytettävyyttä. Tiedämme, että minkään kohteen lämpötila ei voi nousta alle -273,15 celsiusasteeseen (absoluuttinen nolla termodynamiikassa)

Päivitetään koodiamme tämän arvorajoituksen toteuttamiseksi.

Ilmeinen ratkaisu yllä olevaan rajoitukseen on piilottaa attribuutti temperature(tehdä siitä yksityinen) ja määritellä uudet getter- ja setter-menetelmät sen manipuloimiseksi. Tämä voidaan tehdä seuraavasti:

 # 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

Kuten voimme nähdä, yllä oleva menetelmä esittelee kaksi uutta get_temperature()ja set_temperature()menetelmää.

Lisäksi temperaturekorvattiin _temperature. Alaviivaa _alussa käytetään yksityisten muuttujien merkitsemiseen Pythonissa.

Käytetään nyt tätä toteutusta:

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

Tuotos

 37 98.60000000000001 Jäljitys (viimeisin puhelu viimeisin): Tiedosto "", rivi 30, Tiedosto "", rivi 16, set_temperature ArvoVirhe: Lämpötila alle -273,15 ei ole mahdollinen.

Tämä päivitys otti uuden rajoituksen käyttöön. Emme saa enää asettaa lämpötilaa alle -273,15 celsiusastetta.

Huomaa : Yksityisiä muuttujia ei todellakaan ole Pythonissa. On yksinkertaisesti noudatettava normeja. Kieli itsessään ei sovi mitään rajoituksia.

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

Kuitenkin suurempi ongelma edellä päivitys on, että kaikki ohjelmat, jotka toteutetaan edellisessä luokan on muuttamaan koodia obj.temperatureja obj.get_temperature()ja kaikki ilmauksia, kuten obj.temperature = valon obj.set_temperature(val).

Tämä uudelleenrakentaminen voi aiheuttaa ongelmia käsiteltäessä satoja tuhansia koodirivejä.

Kaiken kaikkiaan uusi päivitys ei ollut taaksepäin yhteensopiva. Täältä @propertytulee pelastus.

Ominaisuusluokka

Pythoninen tapa käsitellä yllä olevaa ongelmaa on käyttää propertyluokkaa. Näin voimme päivittää koodimme:

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

Lisäsimme print()toiminnon sisälle get_temperature()ja set_temperature()havaitsemme selvästi, että niitä suoritetaan.

Koodin viimeinen rivi tekee ominaisuusobjektista temperature. Yksinkertaisesti sanottuna ominaisuus liittää osan koodista ( get_temperatureja set_temperature) jäsenmääritteen pääsyihin ( temperature).

Käytetään tätä päivityskoodia:

 # 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

Tuotos

 Asetusarvo… Arvon saaminen … 37 Arvon saaminen … 98.6000000000000001 Asetusarvo… Traceback (viimeisin puhelu viimeisin): Tiedosto "", rivi 31, Tiedosto "", rivi 18, set_temperature Arvo Virhe: Lämpötila alle -273 ei ole mahdollinen

Kuten voimme nähdä, kaikki koodit, jotka noutavat arvon, temperaturesoittavat automaattisesti get_temperature()sanakirjan (__dict__) haun sijaan. Vastaavasti kaikki koodit, joille arvo temperatureannetaan, soittaa automaattisesti set_temperature().

Voimme jopa nähdä yllä, set_temperature()jota kutsuttiin, vaikka loimme objektin.

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

Voitteko arvata miksi?

Syynä on, että kun objekti luodaan, __init__()menetelmä kutsutaan. Tällä menetelmällä on rivi self.temperature = temperature. Tämä lauseke kutsuu automaattisesti set_temperature().

Vastaavasti kaikki käyttöoikeudet, kuten c.temperatureautomaattiset puhelut get_temperature(). Tätä omaisuus tekee. Tässä on muutama esimerkki.

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

Käyttämällä propertyvoimme nähdä, että mitään muutosta ei tarvita arvorajoituksen toteuttamisessa. Täten toteutuksemme on taaksepäin yhteensopiva.

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)

Nämä kaksi koodia ovat vastaavia.

Python-sisustajia tuntevat ohjelmoijat voivat tunnistaa, että yllä oleva rakenne voidaan toteuttaa sisustajina.

Voimme jopa ei määritellä nimiä get_temperatureja set_temperaturekoska ne ovat tarpeettomia ja saastuttaa luokan nimiavaruuteen.

Tätä varten käytämme temperaturenimeä uudelleen määrittäessämme getter- ja setter-toimintoja. Katsotaanpa, miten tämä voidaan toteuttaa sisustajana:

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

Tuotos

 Asetusarvo… Arvoa haetaan … 37 Arvoa haetaan … 98.6000000000000001 Asetusarvo… Traceback (viimeisin puhelu viimeisin): Tiedosto "", rivi 29, Tiedosto "", rivi 4, __init__ Tiedosto "", rivi 18, lämpötilassa ValueError: Lämpötila alle -273 ei ole mahdollista

Edellä mainittu toteutus on yksinkertainen ja tehokas. Se on suositeltava käyttötapa property.

Mielenkiintoisia artikkeleita...