création de propriétés à la volée

Licence CC BY-NC-ND Thierry Parmentelat & Arnaud Legout

création de propriétés à la volée#

en s’inspirant du code:#

class Person(object):
    def __init__(self):
        self._name = ''

    def fget(self):
        print(f"Getting: {self._name}")
        return self._name

    def fset(self, value):
        print(f"Setting: {value}")
        self._name = value.title()

    name = property(fget=fget, fset=fset, doc="I'm the property.")
user = Person()
user.name = 'john smith'
Setting: john smith
# remarquez d'ailleurs - sans rapport avec l'exercice
# qu'ici on ne spécifie pas de deleter
try:
    del user.name
except AttributeError as e:
    print("OOPS", e)
OOPS property 'name' of 'Person' object has no deleter

écrivez#

  • une nouvelle version DynamicPerson de cette classe

  • qui ne possède plus les 2 méthodes fget/fset

  • mais en remplacement une méthode addProperty

    • et autres méthodes privées si nécessaire

  • de façon à ce qu’on puisse l’utiliser comme ceci

>>> user = DynamicPerson()
>>> user.addProperty('name')
>>> user.addProperty('phone')
>>> user.name = 'john smith'
Setting: name = john smith
>>> user.phone = '12345'
Setting: phone = 12345
>>> user.name
Getting: name
'John Smith'
>>> user.__dict__
{'_phone': '12345', '_name': 'John Smith'}

indices#

  • pour cet exercice il semble plus naturel

    • d’utiliser la builtin property

    • plutôt que la version avec décorateur

  • remarquez que le récepteur de addProperty

    • est l’instance user

    • et non la classe Person

# une façon possible de faire

class DynamicPerson(object):

    def addProperty(self, attribute):
        # avec une clôture on capture attribute
        # dans les getter et setter
        def setter(self, value):
            print(f"Setting: {attribute} = {value}")
            setattr(self, '_' + attribute, value)
        def getter(self):
            value = getattr(self, '_' + attribute)
            print(f"Getting: {attribute} = {value}")
            return value
        # on attache la property à la classe et pas à l'instance
        setattr(self.__class__,
                attribute,
                # le descriptor fabriqué par property
                property(fget=getter,
                         fset=setter,
                         doc=f"Auto-generated {attribute} method"))
user = DynamicPerson()
user.addProperty('name')
user.addProperty('phone')
user.name = 'john smith'
user.phone = '12345'
user.name
user.__dict__
Setting: name = john smith
Setting: phone = 12345
Getting: name = john smith
{'_name': 'john smith', '_phone': '12345'}

pour les rapides#

  • ajoutez du code de sorte que

    • addProperty()

    • crée l’attribut à une valeur None

    • ou encore mieux, à une valeur passée à addProperty