IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Boucler sur les attributs d'une classe à l'aide d'un dictionnaire [Python 3.X]


Sujet :

Python

  1. #1
    Membre averti
    Homme Profil pro
    Architecte réseau
    Inscrit en
    Janvier 2016
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Architecte réseau

    Informations forums :
    Inscription : Janvier 2016
    Messages : 36
    Par défaut Boucler sur les attributs d'une classe à l'aide d'un dictionnaire
    Bonjour,

    Je pensais pouvoir modifier les attributs d'une classe par le biais d'un dictionnaire, mais jusqu'ici sans succès...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    class SensorSeries:
     
        def __init__(self,name):
            self.name = name
            self.units = 'units'
            self.ylim = (0,100)
            self.ylabel = 'Y label'
            self.title = name
            self.data = []
     
     
    dico_1 = {"units":"Nouvelle unité","ylim":(0,675),"ylabel":"Nouveau label","title":"Nouveau titre"}
     
    serie_1 = SensorSeries('Initial name')
     
    print("-----------------------------------")
     
    for dico_key, dico_value in dico_1.items():
        print (f'dico_key :{dico_key} ; dico_value :{dico_value}')# j'extrais bien les valeurs désirées du dictionnaire
        serie_1.dico_key = dico_value # <--- mais ici ça ne fonctionne pas comme je l'imaginais... je ne parviens pas à changer les attributs de serie_1
     
    print("-----------------------------------")
     
    print (serie_1.name)
    print (serie_1.units)
    print (serie_1.ylim)
    print (serie_1.ylabel)
    print (serie_1.title)
    -----------------------------------
    dico_key :units ; dico_value :Nouvelle unité
    dico_key :ylim ; dico_value :(0, 675)
    dico_key :ylabel ; dico_value :Nouveau label
    dico_key :title ; dico_value :Nouveau titre
    -----------------------------------
    Initial name
    units
    (0, 100)
    Y label
    Initial name


    Peut-on faire référence à un attribut de classe de façon indirecte, par le biais d'une variable ? (ici dico_key)

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 746
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 746
    Par défaut
    Salut,

    Citation Envoyé par scarou Voir le message
    Peut-on faire référence à un attribut de classe de façon indirecte, par le biais d'une variable ? (ici dico_key)
    dico_key est surtout une chaîne de caractère. Donc la question serait plutôt l'accès aux attributs via leur noms. C'est ce que font les builtins setattr, hasattr, getattr, delattr.

    Maintenant, appliquer setattr(...) sans s'assurer que le nom de l'attribut est valide, c'est ouvrir la porte à de mauvaises surprises.... Surtout si ce n'est pas une méthode qui fait le boulot de vérification et de mise à jour (une fonction peut être dans un module différent de celui où est définie la "class"... pas facile de rester cohérent!).

    - W

    ps: on peut mettre à jour le dictionnaire des attributs de la class... mais, trop sale pour vous le montrer.
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    On peut se poser la question de vouloir modifier un objet d'un telle façon...

    Soit c'est une possibilité offerte par la classe et alors il faudrait ajouter une méthode setMetadata(dico) à la classe SensorSeries. C'est propre, c'est clair, c'est maintenue par la classe. Il se pourrait même que des méthodes comme setTitle(title), setUnit(unit) ou encore setLimits(limits) soient encore mieux.

    Soit c'est du gros hacking, et quitte à être sale, autant être efficace....

  4. #4
    Membre averti
    Homme Profil pro
    Architecte réseau
    Inscrit en
    Janvier 2016
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Architecte réseau

    Informations forums :
    Inscription : Janvier 2016
    Messages : 36
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for dico_key, dico_value in dico_1.items():
        print (f'dico_key :{dico_key} ; dico_value :{dico_value}')
        setattr(serie_1,dico_key, dico_value )
    setattr a très bien fait le job merci :)

    Initial name
    units
    (0, 100)
    Y label
    Initial name
    -----------------------------------
    dico_key :units ; dico_value :Nouvelle unité
    dico_key :ylim ; dico_value :(0, 675)
    dico_key :ylabel ; dico_value :Nouveau label
    dico_key :title ; dico_value :Nouveau titre
    -----------------------------------
    Initial name
    Nouvelle unité
    (0, 675)
    Nouveau label
    Nouveau titre

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Soit c'est une possibilité offerte par la classe et alors il faudrait ajouter une méthode setMetadata(dico) à la classe SensorSeries. C'est propre, c'est clair, c'est maintenue par la classe. Il se pourrait même que des méthodes comme setTitle(title), setUnit(unit) ou encore setLimits(limits) soient encore mieux.
    Bonjour
    Dans ce cas, on peut encapsuler ta méthode setXXX dans un getter/setter. Ca fonctionne pareil mais ça s'utilise comme une affectation (via le "égal"). Et on peut en plus contrôler ce qui rentre. Et avec le getter on peut utiliser alors le nom directement comme un membre.

    Exemple:
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class SensorSeries(object):
    	# La fonction qui servira lors de l'affectation
    	def __setName(self, name):
    		if not name:
    			raise ValueError("Pas de nom vide")
    		self.__name=name
    	# Le getter/setter proprement dit
    	name=property(
    		lambda self: "name=[%s]" % self.__name,				# Ici on place la fonction de type getter (une lambda suffit)
    		__setName,							# Ici on place la fonction de type setter (là il faut une vraie fonction car généralement elle fait un traitement complexe)
    	)
     
    	def __init__(self, name):
    		self.__name=name
     
    xxx=SensorSeries("toto")
    print(xxx.name)
    xxx.name="titi"
    print(xxx.name)
    xxx.name=""
    print(xxx.name)

    Et le résultat
    name=[toto]
    name=[titi]
    Traceback (most recent call last):
    File "a.py", line 22, in <module>
    xxx.name=""
    File "a.py", line 7, in __setName
    raise ValueError("Pas de nom vide")
    ValueError: Pas de nom vide
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 746
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 746
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Il se pourrait même que des méthodes comme setTitle(title), setUnit(unit) ou encore setLimits(limits) soient encore mieux.
    Le soucis est que partant d'un dictionnaire genre {"units":"Nouvelle unité" }, il faut passer du nom de la clef à l'attribut que celui ci soit "variable" ou méthode... on devra utiliser XXXattr différemment i.e. faire getattr(object, 'set%s' % key)(value) plutôt que setattr(object, key, value).
    L'avantage est que le getattr plantera si la clef est erronée alors que setattr ajoutera un attribut sans crier gare... et le risque de passer du temps à détecter la faute de frappe. Mais on peut quand même prendre des précautions:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        if hasattr(object, key):
              setattr(objet, key, value)
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre averti
    Homme Profil pro
    Architecte réseau
    Inscrit en
    Janvier 2016
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Architecte réseau

    Informations forums :
    Inscription : Janvier 2016
    Messages : 36
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    L'avantage est que le getattr plantera si la clef est erronée alors que setattr ajoutera un attribut sans crier gare... et le risque de passer du temps à détecter la faute de frappe. Mais on peut quand même prendre des précautions:
    - W
    Bingo ! Celle-là aussi je viens de la faire... en voulant changer des valeurs dans le dico, j'ai par inattention changé les étiquettes... Du coup merci pour l'idée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for dico_key, dico_value in dico_1.items():
    	print (f'dico_key :{dico_key} ; dico_value :{dico_value}')
    	if hasattr(serie_1, dico_key):
    		setattr(serie_1, dico_key, dico_value)
    	else:
    		print(f'!-->{dico_key}<--! is not an attribut of {serie_1.name} object')

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 746
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 746
    Par défaut
    Citation Envoyé par scarou Voir le message
    Bingo ! Celle-là aussi je viens de la faire... en voulant changer des valeurs dans le dico, j'ai par inattention changé les étiquettes... Du coup merci pour l'idée :
    ah ben oui, les fautes d'inattention sont difficiles à rattraper surtout que Python est interprété.
    Cette construction peut aussi aider:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class A:
        def __init__(self, a, b, c):
            self.a = a
            self.b = b
            self.c = c
     
        def update(self, a=0, b=0, c=0):
            self.a = a
            self.b = b
            self.c = c
     
        def __str__(self):
            return 'a=%(a)s, b=%(b)s, c=%(c)s' % vars(self)
     
    obj = A(1, 2, 3)
    d = dict(a=3, b=4, c=5)
    obj.update(**d)
    print(obj)
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Boucle sur les attributs d'une classe
    Par lefty972 dans le forum Langage
    Réponses: 1
    Dernier message: 21/06/2012, 19h04
  2. Réponses: 5
    Dernier message: 07/05/2012, 17h20
  3. [Flex4] binding sur les attributs d'une classe
    Par j-jorge dans le forum Flex
    Réponses: 1
    Dernier message: 09/09/2010, 13h26
  4. Réponses: 2
    Dernier message: 17/04/2007, 17h14
  5. Réponses: 7
    Dernier message: 08/01/2005, 13h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo