Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Industrial programming >> Python

Python @property decorateur

Python @property decorateur

In deze tutorial leer je over Python @property decorateur; een pythonische manier om getters en setters te gebruiken in objectgeoriënteerd programmeren.

Python-programmering biedt ons een ingebouwde @property decorateur die het gebruik van getter en setters veel gemakkelijker maakt in objectgeoriënteerd programmeren.

Voordat we ingaan op details over wat @property decorateur is, laten we eerst een intuïtie bouwen over waarom het in de eerste plaats nodig zou zijn.


Klasse zonder getters en setters

Laten we aannemen dat we besluiten een klasse te maken die de temperatuur opslaat in graden Celsius. Het zou ook een methode implementeren om de temperatuur om te zetten in graden Fahrenheit. Een manier om dit te doen is als volgt:

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

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

We kunnen objecten van deze klasse maken en de temperature . manipuleren attribuut zoals we willen:

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

Uitvoer

37
98.60000000000001

De extra decimalen bij het converteren naar Fahrenheit zijn te wijten aan de rekenfout met drijvende komma. Ga voor meer informatie naar Python Floating Point Rekenfout.

Telkens wanneer we een objectattribuut toewijzen of ophalen, zoals temperature zoals hierboven weergegeven, zoekt Python het in de ingebouwde __dict__ . van het object woordenboekkenmerk.

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

Daarom man.temperature intern wordt man.__dict__['temperature'] .


getters en setters gebruiken

Stel dat we de bruikbaarheid van de Celsius . willen uitbreiden hierboven gedefinieerde klasse. We weten dat de temperatuur van elk object niet lager kan zijn dan -273,15 graden Celsius (absoluut nulpunt in de thermodynamica)

Laten we onze code bijwerken om deze waardebeperking te implementeren.

Een voor de hand liggende oplossing voor de bovenstaande beperking is het verbergen van het attribuut temperature (maak het privé) en definieer nieuwe getter- en setter-methoden om het te manipuleren. Dit kan als volgt worden gedaan:

# 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

Zoals we kunnen zien, introduceert de bovenstaande methode twee nieuwe get_temperature() en set_temperature() methoden.

Verder, temperature werd vervangen door _temperature . Een onderstrepingsteken _ aan het begin wordt gebruikt om privévariabelen in Python aan te duiden.


Laten we nu deze implementatie gebruiken:

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

Uitvoer

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.

Deze update heeft de nieuwe beperking succesvol geïmplementeerd. We mogen de temperatuur niet meer onder de -273,15 graden Celsius zetten.

Opmerking :De privévariabelen bestaan ​​niet echt in Python. Er zijn gewoon normen waaraan moet worden voldaan. De taal zelf kent geen beperkingen.

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

Het grotere probleem met de bovenstaande update is echter dat alle programma's die onze vorige klasse hebben geïmplementeerd hun code moeten wijzigen van obj.temperature tot obj.get_temperature() en alle uitdrukkingen zoals obj.temperature = val tot obj.set_temperature(val) .

Deze refactoring kan problemen veroorzaken bij het omgaan met honderdduizenden regels codes.

Al met al was onze nieuwe update niet achterwaarts compatibel. Dit is waar @property komt te hulp.


De eigenschapsklasse

Een pythonische manier om met het bovenstaande probleem om te gaan, is door de property . te gebruiken klas. Hier is hoe we onze code kunnen updaten:

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

We hebben een print() . toegevoegd functie binnen get_temperature() en set_temperature() om duidelijk te zien dat ze worden uitgevoerd.

De laatste regel van de code maakt een eigenschapsobject temperature . Simpel gezegd, eigendom voegt een code toe (get_temperature en set_temperature ) naar de lidattribuuttoegangen (temperature ).

Laten we deze updatecode gebruiken:

# 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

Uitvoer

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

Zoals we kunnen zien, kan elke code die de waarde van temperature belt automatisch get_temperature() in plaats van een woordenboek (__dict__) look-up. Evenzo, elke code die een waarde toekent aan temperature belt automatisch set_temperature() .

We kunnen hierboven zelfs zien dat set_temperature() werd aangeroepen, zelfs toen we een object maakten.

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

Kun je raden waarom?

De reden is dat wanneer een object wordt gemaakt, de __init__() methode wordt aangeroepen. Deze methode heeft de regel self.temperature = temperature . Deze uitdrukking roept automatisch set_temperature() . aan .

Evenzo kan elke toegang zoals c.temperature belt automatisch get_temperature() . Dit is wat eigendom doet. Hier zijn nog een paar voorbeelden.

>>> human.temperature
Getting value
37
>>> human.temperature = 37
Setting value

>>> c.to_fahrenheit()
Getting value
98.60000000000001

Door property . te gebruiken , kunnen we zien dat er geen wijziging nodig is bij de implementatie van de waardebeperking. Onze implementatie is dus achterwaarts compatibel.

Opmerking :De werkelijke temperatuurwaarde wordt opgeslagen in de privé _temperature variabel. De temperature attribuut is een eigenschapsobject dat een interface biedt voor deze privévariabele.


De @property Decorateur

In Python, property() is een ingebouwde functie die een property . maakt en retourneert object. De syntaxis van deze functie is:

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

waar,

  • fget is functie om de waarde van het attribuut te krijgen
  • fset is functie om de waarde van het attribuut in te stellen
  • fdel is functie om het attribuut te verwijderen
  • doc is een string (zoals een opmerking)

Zoals uit de implementatie blijkt, zijn deze functieargumenten optioneel. Een eigenschapsobject kan dus eenvoudig als volgt worden aangemaakt.

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

Een eigenschapsobject heeft drie methoden, getter() , setter() , en deleter() om fget op te geven , fset en fdel op een later moment. Dit betekent de regel:

temperature = property(get_temperature,set_temperature)

kan worden onderverdeeld als:

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

Deze twee stukjes codes zijn equivalent.

Programmeurs die bekend zijn met Python Decorators kunnen herkennen dat de bovenstaande constructie kan worden geïmplementeerd als decorateurs.

We kunnen de namen get_temperature zelfs niet definiëren en set_temperature omdat ze niet nodig zijn en de klassenaamruimte vervuilen.

Hiervoor hergebruiken we de temperature naam bij het definiëren van onze getter- en setterfuncties. Laten we eens kijken hoe we dit als decorateur kunnen implementeren:

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

Uitvoer

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

De bovenstaande implementatie is eenvoudig en efficiënt. Het is de aanbevolen manier om property . te gebruiken .


Python

  1. Python-gegevenstypen
  2. Python-operators
  3. Python pass-instructie
  4. Python-functieargumenten
  5. Python-woordenboek
  6. Python-overerving
  7. Overbelasting van Python-operator
  8. Python-iterators
  9. Python-sluitingen
  10. Python @property decorateur
  11. Python datetime