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 :

Classe : empêcher la création dynamique de nouveaux attributs


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut Classe : empêcher la création dynamique de nouveaux attributs
    Voici un code qui me gêne un peu.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class UneClasse:
        """exemple d'une classe"""
        champ1 = "abc"
        def f (self):
                return champ1
     
    a = UneClasse()
    a.champ1
    'abc'
    a.chmap1 = "bcd"
     
    print dir(a)
    Ce code renvoie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ['__doc__', '__module__', 'champ1', 'chmap1', 'f']
    On voie qu'un nouvel attribut a été créé. Je connaissais ce principe. Peut-on l'empêcher ? Pourquoi ? S'il on souhaite utiliser Python avec des débutants, il serait beaucoup mieux que l'on puisse empêcher cela.

    Toute info. est la bienvenue, sauf si ce comportement n'est plus présent dans Python 3 (que je n'ai pas sous la main).

  2. #2
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut
    Citation Envoyé par rambc Voir le message
    S'il on souhaite utiliser Python avec des débutants, il serait beaucoup mieux que l'on puisse empêcher cela.
    J'ai fait mes premiers pas en orienté objet avec Python, et je n'ai jamais été gené par cette propriété.
    Au contraire, ça permet de définir des attributs "à l'arrache" dans les méthodes, ce qui simplifie vachement pour un débutant.

    Mais il existe une solution: __slots__
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    In [1]: class UneClass(object):
       ...:     __slots__ = ("attr1", "attr2")
       ...:
       ...:
     
    In [2]: u = UneClass()
     
    In [3]: u.hello = "haha"
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
     
    C:\Windows\system32\<ipython console> in <module>()
     
    AttributeError: 'UneClass' object has no attribute 'hello'
    Note: à partir de Python 3, il n'est plus nécessaire de dériver d'object.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    29
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 29
    Par défaut
    Bonjour, cela est faisable en surchargeant ou en créant une méthode __setattr__ dans la classe en question dont tu permetter ou non les données pouvant être crées ou non.
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    >>> class A:
    ...     def __setattr__(self, dat, val):
    ...             pass
    ...
    >>> r = A()
    >>> dir(r)
    ['__doc__', '__module__', '__setattr__']
    >>> r.newvar = 339
    >>> dir(r)
    ['__doc__', '__module__', '__setattr__']

  4. #4
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Merci Antoine_935 pour cette astuce.

    Cela peut être très utile si tu distribues un module et que tu veux aider les futurs utilisateurs en cas de faute de frappe.

    Sinon comme je le dis ci-dessus, je me plaçais d'un point de vue de débutant. J'aurais dû préciser que je pensais à des lycéens qui aurait très peu programmé.

    Oups la mort m'a eu par surprise...

    the-death, ta méthode est très bien car elle ne nécessite pas de mettre à la main tous les attributs (chose que j'aurais refusé de faire). C'est nickel.

  5. #5
    Membre émérite
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Par défaut
    Citation Envoyé par rambc Voir le message
    the-death, ta méthode est très bien car elle ne nécessite pas de mettre à la main tous les attributs (chose que j'aurais refusé de faire). C'est nickel.
    Oula... le jour où tu voudras faire du C, C++, PHP, Java, C# tu vas pas aimer toi... Eh oui, faut les déclarer les attributs.

    Sinon, euh...
    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
    In [7]: class A:
       ...:     def __init__(self):
       ...:         self.myValue = 5
       ...:
       ...:     def __setattr__(self, attr, value):
       ...:         pass
       ...:
       ...:
     
    In [8]: a = A()
     
    In [9]: a.myValue
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
     
    C:\Windows\system32\<ipython console> in <module>()
     
    AttributeError: A instance has no attribute 'myValue'
    Haha, pratique...

  6. #6
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Citation Envoyé par Antoine_935 Voir le message
    Oula... le jour où tu voudras faire du C, C++, PHP, Java, C# tu vas pas aimer toi... Eh oui, faut les déclarer les attributs.
    Ne m'en parles pas, j'ai du mal car je trouve cela très verbeux. Ceci étant dit, le jour où la lenteur de Python sera critique dans mon application, je passerais au C++. Sinon je parlais de cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    __slots__ = ("attr1", "attr2")
    A comparer avec cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    self.attr1 = value1
    self.attr1 = value2
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int attr1 = value1
    string attr1 = value2
    La seconde méthode donne en plus le choix de gestion des attributs créés à la volée.

  7. #7
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut @ rambc
    1) Où en es-tu de ce problème ?

    As-tu trouvé une solution ?
    La file est taguée ’Résolu’ mais je ne vois pas s’il y en a une dans cette file.





    2) Comme tu as l’air de préférer la “solution“ de the-death, j’ai regardé un peu. Il est facile de corriger son inconvénient pointé par Antoine935 en complexifiant la méthode __setattr__() . Elle est très bien cette méthode.
    De plus, l’attribut __slots__ n’existe que pour les classes dérivées d’object (classes de nouvelle facture).

    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
    class A:
        champ1 = "abc"
        def __init__(self,n):
            print "debut d'initialisation d'une instance"
            self.myValue = 5
            self.name = n
            self.__dict__['ini'] = 'faite'
            print "fin de l'initialisation de l'instance de  nom  \""+n+'"\n'
        def __setattr__(self, attr, value):
            if 'ini' in self.__dict__:
                print "Il n'est pas possible de definir des champs d'instance supplementaires:"\
                      +"\nvotre demande de creation du champ d'instance \""+attr+'" est rejetee.'
            else:
                self.__dict__[attr] = value
                print "- je viens de creer l'attribut "+attr+" avec la valeur "+repr(value)
     
    a = A('SERENGUETI')
    print 'a.champ1 :',a.champ1
    print '\ndir(a) : ',dir(a)
    print "\n* Tentative de creation du champ d'instance chmap1"
    a.chmap1 = "bcd"
    print 'dir(a) : ',dir(a)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    debut d'initialisation d'une instance
    - je viens de creer l'attribut myValue avec la valeur 5
    - je viens de creer l'attribut name avec la valeur 'SERENGUETI'
    fin de l'initialisation de l'instance de  nom  "SERENGUETI"
     
    a.champ1 : abc
     
    dir(a) :  ['__doc__', '__init__', '__module__', '__setattr__', 'champ1', 'ini', 'myValue', 'name']
     
    * Tentative de creation du champ d'instance chmap1
    Il n'est pas possible de definir des champs d'instance supplementaires:
    votre demande de creation du champ d'instance "chmap1" est rejetee.
    dir(a) :  ['__doc__', '__init__', '__module__', '__setattr__', 'champ1', 'ini', 'myValue', 'name']

    3) Par ailleurs, j’aimerais comprendre ce que tu sous-entend en disant qu’il faut comparer
    __slots__ = ("attr1", "attr2")
    à
    self.attr1 = value1
    self.attr1 = value2

    et

    int attr1 = value1
    string attr1 = value2
    Veux-tu dire que l’utilisation de __slots__ ne définit pas les valeurs des champs et que ça oblige à faire les choses en deux endroits dans le code ?






    int attr1 = value1
    string attr1 = value2
    Ces instructions ne peuvent pas être mises dans __init__() , uh ? Alors qu’est-ce qu’elles montrent ?






    La seconde méthode donne en plus le choix de gestion des attributs créés à la volée.
    N’est ce pas ce que tu veux empêcher: la création d’attributs à la volée ?




    ----------------------------------------------

    J’ai d’autres remarques mais pour ne pas alourdir, je les renvoie à plus tard.

  8. #8
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Citation Envoyé par eyquem Voir le message
    As-tu trouvé une solution ?
    Celle de the-death me va.

    Citation Envoyé par eyquem Voir le message
    Comme tu as l’air de préférer la “solution“ de the-death, j’ai regardé un peu. Il est facile de corriger son inconvénient pointé par Antoine935 en complexifiant la méthode __setattr__()
    Effectivement, je n'ai rien posté car ce qu'a dit the-death me parait très clair.

    J'ai pas trop le temps aujourd'hui. A quoi servent tes modifications ?

    Citation Envoyé par eyquem Voir le message
    Veux-tu dire que l’utilisation de __slots__ ne définit pas les valeurs des champs et que ça oblige à faire les choses en deux endroits dans le code ?
    Oui.

    Citation Envoyé par eyquem Voir le message
    N’est ce pas ce que tu veux empêcher: la création d’attributs à la volée ?
    Je parlais côté concepteur et non côté utilisateur.

  9. #9
    Membre éprouvé

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int attr1 = value1
    string attr1 = value2
    C'était juste un exemple de type C++.

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

Discussions similaires

  1. création dynamique de classes
    Par r83 dans le forum Windows Forms
    Réponses: 2
    Dernier message: 16/12/2008, 17h04
  2. Réponses: 3
    Dernier message: 06/02/2008, 18h11
  3. Réponses: 1
    Dernier message: 19/07/2007, 12h39
  4. [POO] Création dynamique de variables de classe
    Par Philoulheinz dans le forum Langage
    Réponses: 2
    Dernier message: 24/03/2007, 15h38
  5. Création dynamique de méthode sur une classe ?
    Par elitost dans le forum Général Java
    Réponses: 9
    Dernier message: 18/10/2005, 14h47

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