Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> Python

Python @property decorator

Python @property decorator

In diesem Tutorial lernen Sie Python @property decorator kennen; eine pythonische Art, Getter und Setter in der objektorientierten Programmierung zu verwenden.

Die Python-Programmierung stellt uns einen integrierten @property zur Verfügung decorator, der die Verwendung von Getter und Setter in der objektorientierten Programmierung viel einfacher macht.

Bevor wir ins Detail gehen, was @property decorator ist, lassen Sie uns zunächst eine Intuition darüber aufbauen, warum er überhaupt benötigt wird.


Klasse ohne Getter und Setter

Nehmen wir an, wir entscheiden uns für eine Klasse, die die Temperatur in Grad Celsius speichert. Es würde auch eine Methode implementieren, um die Temperatur in Grad Fahrenheit umzuwandeln. Eine Möglichkeit, dies zu tun, ist wie folgt:

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

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

Wir können Objekte aus dieser Klasse machen und den temperature manipulieren Attribut nach Belieben:

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

Ausgabe

37
98.60000000000001

Die zusätzlichen Dezimalstellen bei der Umrechnung in Fahrenheit sind auf den Fließkomma-Arithmetikfehler zurückzuführen. Weitere Informationen finden Sie unter Python Floating Point Arithmetic Error.

Wann immer wir ein Objektattribut wie temperature zuweisen oder abrufen Wie oben gezeigt, sucht Python im integrierten __dict__ des Objekts Dictionary-Attribut.

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

Daher man.temperature wird intern zu man.__dict__['temperature'] .


Getter und Setter verwenden

Angenommen, wir möchten die Benutzerfreundlichkeit von Celsius erweitern oben definierte Klasse. Wir wissen, dass die Temperatur eines Objekts nicht unter -273,15 Grad Celsius sinken kann (absoluter Nullpunkt in der Thermodynamik)

Lassen Sie uns unseren Code aktualisieren, um diese Wertbeschränkung zu implementieren.

Eine offensichtliche Lösung für die obige Einschränkung ist das Ausblenden des Attributs temperature (machen Sie es privat) und definieren Sie neue Getter- und Setter-Methoden, um es zu manipulieren. Dies kann wie folgt erfolgen:

# 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

Wie wir sehen können, führt die obige Methode zwei neue get_temperature() ein und set_temperature() Methoden.

Außerdem temperature wurde durch _temperature ersetzt . Ein Unterstrich _ am Anfang wird verwendet, um private Variablen in Python zu bezeichnen.


Lassen Sie uns nun diese Implementierung verwenden:

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

Ausgabe

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.

Dieses Update hat die neue Einschränkung erfolgreich implementiert. Wir dürfen die Temperatur nicht mehr unter -273,15 Grad Celsius einstellen.

Hinweis :Die privaten Variablen existieren in Python nicht wirklich. Es gibt einfach Normen, die eingehalten werden müssen. Die Sprache selbst unterliegt keinerlei Beschränkungen.

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

Das größere Problem bei dem obigen Update ist jedoch, dass alle Programme, die unsere vorherige Klasse implementiert haben, ihren Code von obj.temperature ändern müssen bis obj.get_temperature() und alle Ausdrücke wie obj.temperature = val bis obj.set_temperature(val) .

Dieses Refactoring kann Probleme beim Umgang mit Hunderttausenden von Codezeilen verursachen.

Alles in allem war unser neues Update nicht abwärtskompatibel. Hier ist @property kommt zur Rettung.


Die Eigenschaftsklasse

Ein pythonischer Weg, um das obige Problem zu lösen, ist die Verwendung von property Klasse. So können wir unseren Code aktualisieren:

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

Wir haben einen print() hinzugefügt Funktion in get_temperature() und set_temperature() klar zu erkennen, dass sie hingerichtet werden.

Die letzte Zeile des Codes erstellt ein Eigenschaftsobjekt temperature . Einfach ausgedrückt, hängt eine Eigenschaft Code an (get_temperature und set_temperature ) auf die Elementattributzugriffe (temperature ).

Verwenden wir diesen Aktualisierungscode:

# 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

Ausgabe

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

Wie wir sehen können, jeder Code, der den Wert von temperature abruft ruft automatisch get_temperature() an anstelle einer Wörterbuchsuche (__dict__). Ebenso jeder Code, der temperature einen Wert zuweist ruft automatisch set_temperature() an .

Wir können sogar darüber set_temperature() sehen wurde aufgerufen, selbst wenn wir ein Objekt erstellt haben.

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

Kannst du erraten, warum?

Der Grund dafür ist, dass beim Erstellen eines Objekts der __init__() Methode aufgerufen wird. Diese Methode hat die Zeile self.temperature = temperature . Dieser Ausdruck ruft automatisch set_temperature() auf .

Ebenso jeder Zugriff wie c.temperature ruft automatisch get_temperature() auf . Dies ist, was Eigentum tut. Hier sind ein paar weitere Beispiele.

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

>>> c.to_fahrenheit()
Getting value
98.60000000000001

Durch die Verwendung von property , können wir sehen, dass bei der Implementierung der Wertbeschränkung keine Änderung erforderlich ist. Somit ist unsere Implementierung abwärtskompatibel.

Hinweis :Der aktuelle Temperaturwert wird im privaten _temperature gespeichert Variable. Der temperature Das Attribut ist ein Eigenschaftsobjekt, das eine Schnittstelle zu dieser privaten Variablen bereitstellt.


Der @property Decorator

In Python property() ist eine integrierte Funktion, die einen property erstellt und zurückgibt Objekt. Die Syntax dieser Funktion ist:

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

wo,

Wie aus der Implementierung ersichtlich, sind diese Funktionsargumente optional. Ein Eigenschaftsobjekt kann also einfach wie folgt erstellt werden.

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

Ein Eigenschaftsobjekt hat drei Methoden, getter() , setter() , und deleter() um fget anzugeben , fset und fdel zu einem späteren Zeitpunkt. Das heißt, die Zeile:

temperature = property(get_temperature,set_temperature)

kann wie folgt aufgeschlüsselt werden:

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

Diese beiden Codes sind gleichwertig.

Programmierer, die mit Python Decorators vertraut sind, werden erkennen, dass das obige Konstrukt als Decorators implementiert werden kann.

Wir können nicht einmal die Namen get_temperature definieren und set_temperature da sie unnötig sind und den Klassennamensraum verschmutzen.

Dafür verwenden wir wieder den temperature name beim Definieren unserer Getter- und Setter-Funktionen. Sehen wir uns an, wie dies als Dekorateur implementiert wird:

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

Ausgabe

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

Die obige Implementierung ist einfach und effizient. Dies ist die empfohlene Methode zur Verwendung von property .


Python

  1. Python-Datentypen
  2. Python-Operatoren
  3. Python-pass-Anweisung
  4. Python-Funktionsargumente
  5. Python-Wörterbuch
  6. Python-Vererbung
  7. Überladen von Python-Operatoren
  8. Python-Iteratoren
  9. Python-Schließungen
  10. Python @property decorator