Proprietà

Proprietà vs Attributi

Le proprietà sono modi per ottenere e impostare il valore di alcuni attributi (ma non solo, possono esserci proprietà calcolate) senza dover richiamare le funzioni getter e setter, come abbiamo visto negli esempi fino a qui. Per i programmatori Python, questa è una tecnica usata molto comunemente, considerata l'estrema semplicità di implementazione.

class Fruit(object):
    .....

    @property
    def quality(self):
        return self.__quality

    @quality.setter
    def quality(self, value):
        if 0 <= value <= 100: 
            self.__quality = value
        else:
            self.__quality = 50
            self.__addAlert('bad quality: %d' % value)


def main():
    myapple = Fruit('mela granny smith')
    myapple.quality = 10
    print('quality %d' % myapple.quality)
    print('Allarmi: ', *myapple.getAlerts())
    myapple.quality = -20
    print('quality %d' % myapple.quality)
    print('Allarmi: ', *myapple.getAlerts())

L'output è come il seguente:

quality 10
Allarmi: 
quality 50
Allarmi:  bad quality: -20

Come si vede, nonostante l'uso sia simile a quello degli attributi pubblici, in realtà vengono richiamate le funzioni specifiche impostate.

Uso dell'attributo di classe __slots__

Come abbiamo già visto, si può usare l'attributo di classe __slots__ per indicare una lista di attributi di istanza validi. È sufficiente inserire nel codice la riga

__slots__ = ('name', '__alerts', '__quality')

per far sì che il codice seguente, altrimenti valido, provochi un errore:

myapple = Fruit('mela granny smith')
myapple.quality = 10
myapple.color='verde'
print(myapple.color)

>>> 
Traceback (most recent call last):
  File ".../Fruit.py", line 58, in <module>
    main()
  File "/.../Fruit.py", line 54, in main
    myapple.color='verde'
AttributeError: 'Fruit' object has no attribute 'color'

Proprietà calcolate

Alcune proprietà possono essere calcolate a partire dal valore degli attributi. Per esse si può impostare solo il getter, e non il setter. Ad esempio, si consideri il seguente codice:

@property
def is_good(self):
    return self.quality > 70

Sarà possibile eseguire queste istruzioni:

myapple = Fruit('mela granny smith') 
myapple.quality = 10
print(myapple.quality, myapple.is_good)
myapple.quality = 75
print(myapple.quality, myapple.is_good)

ma non questa:

myapple.is_good = False
# non funziona (manca il setter)

Eliminazione di un attributo

Gli attributi possono essere eliminati. Per farlo, è sufficiente usare la parola chiave del:

>>> f=Foo()  # immaginiamo di avere una classe Foo.
>>> f.bar=1
>>> print(f.bar)
1
>>> del f.bar
>>> print(f.bar)
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    print(f.bar)
AttributeError: 'Foo' object has no attribute 'bar'

Se usiamo le proprietà, possiamo definire una funzione che verrà invocata in occasione della cancellazione:

@quality.deleter
def quality(self):
    del self.__quality

Visto che consentiamo la cancellazione, sarà necessario gestire anche il getter in maniera più articolata, ad esempio con un try... except:

@property
def quality(self):
    '''Quality of the picture. Can be any value between 0 and 100 (included).'''
    try:
        return self.__quality
    except AttributeError as err:
        return None

Già che ci siamo, possiamo aggiungere una stringa di documentazione sulla proprietà, da poter richiamare in caso di necessità:

print(Fruit.quality.__doc__)
Quality of the picture. Can be any value between 0 and 100 (included).

Proprietà impostate senza uso di decoratori

Una proprietà può essere impostata senza uso di decoratori, tramite la funzione predefinita property, che permette di indicare, nell'ordine, getter, setter, deleter e docstring:

def getQuality(self):
    try:
        return self.__quality
    except AttributeError as err:
        return None


def setQuality(self, value):
    if 0 <= value <= 100: 
        self.__quality = value
    else:
        self.__quality = 50
        self.__addAlert('bad quality: %d' % value)

def delQuality(self):
    print('removing quality')
    del self.__quality

quality=property(
    getQuality,
    setQuality,
    delQuality,
    'Quality of the picture. Can be any value between 0 and 100 (included).'
    )

results matching ""

    No results matching ""