@Property Decorator Pythonissa: sen käyttötapaukset, edut ja syntaksit

? Tapaa ominaisuudet

Tervetuloa! Tässä artikkelissa opit työskentelemään @propertysisustajan kanssa Pythonissa.

Sinä tulet oppimaan:

  • Hyödyt Pythonin ominaisuuksien kanssa työskentelystä.
  • Sisustustoimintojen perusteet: mitä ne ovat ja miten ne liittyvät @propertyyn.
  • Kuinka voit käyttää @property-määritellä hautaajat, asettimet ja poistajat.

1️⃣ Pythonin ominaisuuksien edut

Aloitetaan vähän kontekstista. Miksi käyttäisit ominaisuuksia Pythonissa?

Ominaisuuksia voidaan pitää "pythonina" tapana työskennellä määritteiden kanssa, koska:

  • Ominaisuuksien määrittelyssä käytetty syntaksin sisältö on hyvin tiivis ja luettavissa.
  • Voit käyttää ilmentymämääritteitä täsmälleen ikään kuin ne olisivat julkisia määritteitä, samalla kun käytät välittäjien (gettereitä ja asettajia) "taikuutta" uusien arvojen vahvistamiseksi ja tietojen pääsyn tai muokkaamisen välttämiseksi.
  • Käyttämällä @property -toimintoa voit "käyttää" uudelleen ominaisuuden nimeä välttääksesi uusien nimien luomista hahmottimille, asettajille ja poistajille.

Nämä edut tekevät ominaisuuksista todella mahtavan työkalun, jonka avulla voit kirjoittaa suppeamman ja luettavamman koodin. ?

2️⃣ Johdatus sisustajille

Sisustusarkkitehti toiminto on pohjimmiltaan toiminto, joka lisää uusia toimintoja toimintoon välitetään argumentti. Sisustustoiminnon käyttö on kuin suklaa-sprinklien lisääminen jäätelöön? Sen avulla voimme lisätä uusia toimintoja olemassa olevaan toimintoon muuttamatta sitä.

Alla olevasta esimerkistä näet, miltä tyypillinen sisustusfunktio näyttää Pythonissa:

def decorator(f): def new_function(): print("Extra Functionality") f() return new_function @decorator def initial_function(): print("Initial Functionality") initial_function()

Analysoidaan nämä elementit yksityiskohtaisesti:

  • Ensin löydämme koristefunktion def decorator(f)(sprinkles ✨), joka käyttää funktion fargumenttina.
def decorator(f): def new_function(): print("Extra Functionality") f() return new_function
  • Tällä sisustustoiminnolla on sisäkkäinen toiminto new_function. Huomaa, kuinka fsisäpuolella kutsutaan new_functionsaman toiminnallisuuden saavuttamiseksi samalla kun lisätään uusia toimintoja ennen toimintokutsua (voisimme lisätä uusia toimintoja myös toimintokutsun jälkeen).
  • Sisustusfunktio palauttaa sisäkkäisen toiminnon new_function.
  • Sitten (alla) löydämme koristelun (jäätelö?) initial_function. Huomaa @decoratorfunktion otsikon yläpuolella oleva erikoinen syntaksit ( ).
@decorator def initial_function(): print("Initial Functionality") initial_function()

Jos suoritamme koodin, näemme tämän lähdön:

Extra Functionality Initial Functionality

Huomaa, kuinka sisustustoiminto toimii, vaikka soittaisimme vain initial_function(). Tämä on taika lisätä @decorator?

?Huomautus: Yleensä kirjoitamme @korvaamalla sisustustoiminnon nimen @ -merkin jälkeen.

Tiedän, että saatat kysyä: miten tämä liittyy @omaisuuteen? @Property on sisäänrakennettu sisustaja Pythonin ominaisuus () -toiminnolle. Sitä käytetään antamaan "erityinen" toiminnallisuus tietyille menetelmille, jotta ne toimisivat vetäjinä, asettajina tai poistajina, kun määritämme ominaisuuksia luokassa.

Nyt kun olet perehtynyt sisustajiin, katsotaanpa todellinen skenaario @omaisuuden käytöstä!

? Reaalimaailman skenaario: @ omaisuus

Oletetaan, että tämä luokka on osa ohjelmaa. Mallinnat taloa, jolla on Houseluokka (tällä hetkellä luokassa on määritelty vain hinta- ilmentymä-attribuutti):

class House: def __init__(self, price): self.price = price

Tämä ilmentymäattribuutti on julkinen, koska sen nimessä ei ole alaviivaa. Koska attribuutti on tällä hetkellä julkinen, on hyvin todennäköistä, että sinä ja muut tiimisi kehittäjät käyttitte ja muokkaitte attribuuttia suoraan ohjelman muissa osissa pistemerkintöjen avulla seuraavasti:

# Access value obj.price # Modify value obj.price = 40000

? Vinkki: obj edustaa muuttujaa, joka viittaa esiintymään House.

Toistaiseksi kaikki toimii hyvin, eikö? Mutta sanotaan, että sinua pyydetään tekemään tämä attribuutti suojatuksi (ei-julkiseksi) ja vahvistamaan uusi arvo ennen sen määrittämistä . Erityisesti sinun on tarkistettava, onko arvo positiivinen kelluva. Kuinka tekisit sen? Katsotaan.

Koodin vaihtaminen

Tässä vaiheessa, jos päätät lisätä getters ja setters, sinä ja tiimisi todennäköisesti paniikkia? Tämä johtuu siitä, että jokaista koodiriviä, joka käyttää tai muuttaa määritteen arvoa, on muutettava kutsumaan getter tai setter. Muuten koodi rikkoutuu ⚠️.

# Changed from obj.price obj.get_price() # Changed from obj.price = 40000 obj.set_price(40000)

Mutta ... Ominaisuudet tulevat apuun! Kanssa @propertysinun ja tiimisi ei tarvitse muokata mitään näistä linjoista, koska voit lisätä gettereitä ja asettimia "kulissien taakse" vaikuttamatta syntaksiin, jota käytit attribuutin käyttämiseen tai muokkaamiseen, kun se oli julkinen.

Mahtavaa, eikö?  

? @ominaisuus: Syntaksi ja logiikka

Jos päätät käyttää @property, luokkasi näyttää alla olevalta esimerkiltä:

class House: def __init__(self, price): self._price = price @property def price(self): return self._price @price.setter def price(self, new_price): if new_price > 0 and isinstance(new_price, float): self._price = new_price else: print("Please enter a valid price") @price.deleter def price(self): del self._price

Voit määrittää kolme ominaisuutta omaisuudelle:

  • Getter - käyttää arvoa määrite.
  • Setter - asettaa arvo määrite.
  • Deleter - poistaa esimerkiksi määrite.

Hinta on nyt "suojattu"

Please note that the price attribute is now considered "protected" because we added a leading underscore to its name in self._price:

self._price = price

In Python, by convention, when you add a leading underscore to a name, you are telling other developers that it should not be accessed or modified directly outside of the class. It should only be accessed through intermediaries (getters and setters) if they are available.

? Getter

Here we have the getter method:

@property def price(self): return self._price

Notice the syntax:

  • @property - Used to indicate that we are going to define a property. Notice how this immediately improves readability because we can clearly see the purpose of this method.
  • def price(self) - The header. Notice how the getter is named exactly like the property that we are defining: price. This is the name that we will use to access and modify the attribute outside of the class. The method only takes one formal parameter, self, which is a reference to the instance.
  • return self._price - This line is exactly what you would expect in a regular getter. The value of the protected attribute is returned.

Here is an example of the use of the getter method:

>>> house = House(50000.0) # Create instance >>> house.price # Access value 50000.0

Notice how we access the price attribute as if it were a public attribute. We are not changing the syntax at all, but we are actually using the getter as an intermediary to avoid accessing the data directly.

? Setter

Now we have the setter method:

@price.setter def price(self, new_price): if new_price > 0 and isinstance(new_price, float): self._price = new_price else: print("Please enter a valid price")

Notice the syntax:

  • @price.setter - Used to indicate that this is the setter method for the price property. Notice that we are not using @property.setter, we are using @price.setter. The name of the property is included before .setter.
  • def price(self, new_price): - The header and the list of parameters. Notice how the name of the property is used as the name of the setter. We also have a second formal parameter (new_price), which is the new value that will be assigned to the price attribute (if it is valid).
  • Finally, we have the body of the setter where we validate the argument to check if it is a positive float and then, if the argument is valid, we update the value of the attribute. If the value is not valid, a descriptive message is printed. You can choose how to handle invalid values according the needs of your program.

This is an example of the use of the setter method with @property:

>>> house = House(50000.0) # Create instance >>> house.price = 45000.0 # Update value >>> house.price # Access value 45000.0

Notice how we are not changing the syntax, but now we are using an intermediary (the setter) to validate the argument before assigning it. The new value (45000.0) is passed as an argument to the setter :

house.price = 45000.0

If we try to assign an invalid value, we see the descriptive message. We can also check that the value was not updated:

>>> house = House(50000.0) >>> house.price = -50 Please enter a valid price >>> house.price 50000.0

? Tip: This proves that the setter method is working as an intermediary. It is being called "behind the scenes" when we try to update the value, so the descriptive message is displayed when the value is not valid.

? Deleter

Finally, we have the deleter method:

@price.deleter def price(self): del self._price

Notice the syntax:

  • @price.deleter - Used to indicate that this is the deleter method for the price property. Notice that this line is very similar to @price.setter, but now we are defining the deleter method, so we write @price.deleter.
  • def price(self): - The header. This method only has one formal parameter defined, self.
  • del self._price - The body, where we delete the instance attribute.

? Tip: Notice that the name of the property is "reused" for all three methods.

This is an example of the use of the deleter method with @property:

# Create instance >>> house = House(50000.0) # The instance attribute exists >>> house.price 50000.0 # Delete the instance attribute >>> del house.price # The instance attribute doesn't exist >>> house.price Traceback (most recent call last): File "", line 1, in  house.price File "", line 8, in price return self._price AttributeError: 'House' object has no attribute '_price'

The instance attribute was deleted successfully ?. When we try to access it again, an error is thrown because the attribute doesn't exist anymore.

? Some final Tips

You don't necessarily have to define all three methods for every property. You can define read-only properties by only including a getter method. You could also choose to define a getter and setter without a deleter.

If you think that an attribute should only be set when the instance is created or that it should only be modified internally within the class, you can omit the setter.

You can choose which methods to include depending on the context that you are working with.

? In Summary

  • You can define properties with the @property syntax, which is more compact and readable.
  • @property -toimintoa voidaan pitää "pythonisena" tapana määritellä vetäjät, asettimet ja poistimet.
  • Ominaisuuksien määrittelemällä voit muuttaa luokan sisäistä toteutusta vaikuttamatta ohjelmaan, joten voit lisätä hahmottimia, asettimia ja poistajia, jotka toimivat välittäjinä "kulissien takana", jotta vältetään pääsy tietoihin tai niiden muokkaaminen suoraan.

Toivon todella, että pidit artikkelistani ja pidit siitä hyödyllisenä. Saat lisätietoja Pythonin ominaisuuksista ja olio-ohjelmoinnista tutustumalla verkkokurssilleni, joka sisältää yli 6 tuntia videoluentoja, koodausharjoituksia ja miniprojekteja.