Décorateurs - Getters/Setters/Deleters

 

Moyen

  1. Getters
  2. Setters
  3. Deleters

Les décorateurs nous permettent de définir des méthodes de classe que nous pouvons accéder comme des attributs.

Cela nous permet donc d’implémenter des getters, setters et deleters.


Getters

Que se passe-t-il si nous voulons changer la valeur de emp_1.first après l'instanciation ?
Tout devrait bien se passer non?
class Employee:    
    def __init__(self, first, last):
        self.first = first
        self.last = last
        self.email = first + '.' + last + '@email.com'

    def fullname(self):
        return '{} {}'.format(self.first, self.last)

emp_1 = Employee('John', 'Smith')

emp_1.first = 'Jim' #Change "John" en "Jim".

print(emp_1.first)
print(emp_1.email)
print(emp_1.fullname())
>>>
Jim
John.Smith@email.com
Jim Smith
Comme nous pouvons le voir, l'attribut email est resté intacte.
Cela est dut au fait que email a besoin de l'argumentfirst du constructeur (noté 1 sur le code ci-dessus) pour se créer.
Ainsi, changer la valeur de first via l'objet en lui-même (c-a-d self.first) ne va pas affecter email.

Comment faire alors pour le changer comme les autres ?
Pour cela, il faudrait que notre attribut email ne soit pas créer durant l'appel du constructeur.

Ainsi, pourquoi ne pas le créer de la même manière que fullname(), c'est-à-dire sous forme de méthode ?
class Employee:
    def __init__(self, first, last):
        self.first = first
        self.last = last

    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)

    def fullname(self):
        return '{} {}'.format(self.first, self.last)

emp_1 = Employee('John', 'Smith')

emp_1.first = 'Jim'

print(emp_1.first)
print(emp_1.email()) # See here !
print(emp_1.fullname())
>>>
Jim
Jim.Smith@email.com
Jim Smith
Très bien! Cependant, nous voulons comme dans le premier exemple, que email reste un attribut. (En gros, nous voulons écrire emp_1.email et non emp_1.email() )

C'est pourquoi, nous allons utiliser les getters, très populaire lorsqu'il s'agit de récupérer des valeurs.
class Employee:
    def __init__(self, first, last):
        self.first = first
        self.last = last

    #Getters
    @property
    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)

    def fullname(self):
        return '{} {}'.format(self.first, self.last)

emp_1 = Employee('John', 'Smith')

emp_1.first = 'Jim'

print(emp_1.first)
print(emp_1.email)
print(emp_1.fullname())
>>>
Jim
Jim.Smith@email.com
Jim Smith
Comme vous pouvez le voir, email ressemble à une méthode mais est accessible de la même manière qu'un attribut. Exactement ce qu'il nous fallait !

Cela est dû à @property.

Nous pouvons faire de même avec fullname.
class Employee:

    def __init__(self, first, last):
        self.first = first
        self.last = last

    #Getters
    @property
    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)
    
    @property
    def fullname(self):
        return '{} {}'.format(self.first, self.last)

emp_1 = Employee('John', 'Smith')

emp_1.first = 'Jim'

print(emp_1.first)
print(emp_1.email)
print(emp_1.fullname)
>>>
Jim
Jim.Smith@email.com
Jim Smith

Setters

Supposons que nous voulons désormais changer le fullname d'un employé.
class Employee:
    def __init__(self, first, last):
        self.first = first
        self.last = last

    #Getters
    @property
    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)
    
    @property
    def fullname(self):
        return '{} {}'.format(self.first, self.last)

emp_1 = Employee('John', 'Smith')

emp_1.fullname = 'Ferdinand Mom'

print('-> Firstname')
print(emp_1.first)
print('-> Email')
print(emp_1.email)
print('-> Fullname')
print(emp_1.fullname)
>>>
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-26-1c7982e45c41> in <module>()
        16 emp_1 = Employee('John', 'Smith')
        17 
---> 18 emp_1.fullname = 'Ferdinand Mom'
        19 
        20 print('-> Firstname')


AttributeError: can't set attribute
Python nous renvoie une erreur.
Cela signifie qu'il n'est pas possible de changer directement fullname.
Pour cela, nous allons utiliser des setters.
Ces derniers sont utilisés pour changer des valeurs.
class Employee:
    def __init__(self, first, last):
        self.first = first
        self.last = last

    #Getters
    @property
    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)

    @property
    def fullname(self):
        return '{} {}'.format(self.first, self.last)

    #Setters
    @fullname.setter
    def set_fullname(self, name):
        first, last = name.split(' ')
        self.first = first
        self.last = last
        
emp_1 = Employee('John', 'Smith')

emp_1.set_fullname = 'Ferdinand Mom'

print('-> Firstname')
print(emp_1.first)
print('-> Email')
print(emp_1.email)
print('-> Fullname')
print(emp_1.fullname)
>>>
-> Firstname
Ferdinand
-> Email
Ferdinand.Mom@email.com
-> Fullname
Ferdinand Mom

Deleters

Désormais, nous voulons supprimer le fullname d'un employé.
class Employee:

    def __init__(self, first, last):
        self.first = first
        self.last = last

    #Getters
    @property
    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)

    @property
    def fullname(self):
        return '{} {}'.format(self.first, self.last)

    #Setters
    @fullname.setter
    def set_fullname(self, name):
        first, last = name.split(' ')
        self.first = first
        self.last = last

    #Deleters
    @fullname.deleter
    def del_fullname(self):
        print("Delete fullname !")
        self.first = None
        self.last = None


emp_1 = Employee('John', 'Smith')

emp_1.set_fullname = 'Ferdinand Mom'

print('-> Firstname')
print(emp_1.first)
print('-> Email')
print(emp_1.email)
print('-> Fullname')
print(emp_1.fullname)

print('-> Supprime fullname')
del emp_1.del_fullname
print(emp_1.fullname)
>>>
-> Firstname
Ferdinand
-> Email
Ferdinand.Mom@email.com
-> Fullname
Ferdinand Mom
-> Supprime fullname
Delete fullname !
None None

Pour résumer:

Les décorateurs nous permettent de définir des méthodes de classe que nous pouvons accéder comme des attributs.
Il en existe 3 types:
      - Les getters sont généralement utilisés pour récupérer des valeurs.
      - Les setters sont généralement utilisés pour changer des valeurs.
      - Les deleters sont généralement utilisés pour supprimer des valeurs.