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 :

changer dynamiquement la classe d'une instance


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut changer dynamiquement la classe d'une instance
    Bonjour,

    Est-il possible de changer dynamiquement la/les classes d'une instance ?
    Est-ce raisonnable ? Pythonique ?

    Une utilisation possible serait de rajouter dynamiquement un descripteur à une instance (et pas à toutes les autres instances de sa classe).

    Merci d'avance pour vos idées

  2. #2
    Membre expérimenté
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2011
    Messages : 180
    Par défaut Pas de changement de type
    Bonjour,

    En python, tu ne peux pas changer dynamiquement le type d'un objet. Par conséquent pas de changement de classe non plus

    Par contre, dans le cas qui t'occupe tu peux très bien modifier la docstring associée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class A(object):
        u"""
            Documentation ici
        """
        pass
     
     
    if __name__ == "__main__":
        a = A()
        a.__doc__ = u"Quelque chose"
    De même, tu peux aussi ajouter dynamiquement des méthodes et des propriété. Tu peux aussi créer dynamiquement une nouvelle classe
    avec type(...) et instancier un objet de cette nouvelle classe.

    Les possibilités sont très nombreuses. Je te laisse t'amuser avec

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    En python, tu ne peux pas changer dynamiquement le type d'un objet. Par conséquent pas de changement de classe non plus
    Yes we can:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class A(object):
        def test(self):
            print 'A'
     
    class B(object):
        def test(self):
            print 'B'
     
    x = A()
    x.test()
    x.__class__ = B
    x.test()
    Mais ce n'est qu'une implémentation exotique du pattern "State".
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre expérimenté
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2011
    Messages : 180
    Par défaut Oups
    Wiztrick
    Yes, wen can

    Oups !
    Je ne connaissais pas cette possibilité.

    Décidément, Python est encore plus versatile que je ne le croyais

    Ca m'apprendra à poster sans au moins tester.

    Bien fait pour moi

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Citation Envoyé par chticricri Voir le message
    Oups !
    Je ne connaissais pas cette possibilité.
    Décidément, Python est encore plus versatile que je ne le croyais
    C'est pas parce qu'on peut qu'il faut aller systématiquement dans les constructions les plus "obscures" non plus.

    En fait, je n'ai toujours pas compris la question de VV33D, ou plutôt qu'est ce qui empêche d'ajouter un descripteur à une instance via setattr(instance, "key", descriptor(....)).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    Est-il possible de changer dynamiquement la/les classes d'une instance ?
    comme dit précédemment, oui.

    Est-ce raisonnable ?
    Tout dépend du résultat recherche : si pour y parvenir par des moyen plus conventionnels, tu y perds en lisibilité, alors exploites cette facilité.

    Pythonique ?
    Assurément.

    Une utilisation possible serait de rajouter dynamiquement un descripteur à une instance (et pas à toutes les autres instances de sa classe).
    Tu dois t’être trompe de terme, cause je n'arrive pas à voir l’intérêt d'ajouter un descriptor à une instance :
    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
    >>> class Descriptor(object):
    	def __init__(s,val):
    		s.val=val
    		s._type = type(val)
    	def __get__(s, instance, cls):
    		return s.val
    	def __set__(s, instance, v):
    		if type(v) is not s._type:
    			raise TypeError
    		s.val = v
     
     
    >>> class Foo(object):
    	foo = Descriptor('foo')
     
     
    >>> a=Foo()
    >>> a.foo2=Descriptor(5)
    >>> a.foo2
    <__main__.Descriptor object at 0x0000000002B71CC0>
    >>> Foo.b=Descriptor(5)
    >>> a.b
    5
    >>> a.foo
    'foo'
    En fait je ne vois pas le rapport avec le changement de type d'une instance.

    Précises ta requête s'il-te-plaît

  7. #7
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    Tout d'abord merci à vous pour vos réponses.

    Je ne pensais pas que le code de N.tox marche, dans la mesure ou "un descripteur est associé à la classe et non à l'instance". Sa solution semble préférable.

    Je pensais faire la même chose comme suit (Descriptor est grosso modo la classe écrite par N.tox. disons que foo.__set__() va ecrire de informations dans une log)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class foo:pass
    class foo_with_descriptor(object):
        foo = Descriptor('foo')
     
    a= foo()
    b= foo()
    # ...
    if b.needs_logging():
        b.__class__= foo_with_descriptor
    # les prochains appels à b.foo= value vont logger l'information
    # par contre le comportement de a est inaffecté ()
    Un autre exemple d'utilisation me vient à l'esprit. Je veux appliquer une méthode A.f() à un objet qui n'est pas une instance de A. J'ai une erreur si je fais A.f(objet_b), que je peux éviter en changeant temporairement la classe de objet_b.

    Mais ici aussi j'ai l'impression qu'il y a plus simple (existe-t'il un moyen de transformer A.f en une "unbound fonction" qui ne vérifie pas la classe de son argument self ?).

    Donc pour conclure en général, si je n'ai pas d'autre solution simple, ce n'est pas forcément une mauvaise approche. Cela permet de changer dynamiquement l'interface (vue comme un pattern State) d'une instance.

    Voyez vous d'autres écueils ? Par exemple si je change la classe d'une instance, va-t'elle récupérer les classes parentes également ?

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Salut,

    Je ne comprends toujours pas trop ce que vous voulez faire.
    Mais comme Python est "dynamique", on peut réaliser des choses "étranges"...

    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
    >>> def foo(self): print self.__class__.__name__
    ...
    >>> # collage de la fonction dans A
    >>> class A(object): f = foo
    ...
    >>> class B(object): pass
    ...
    >>> A().f()
    A
    >>> # recuperation de la fonction...
    >>> zz = A.__dict__.get('f')
    >>> zz
    <function foo at 0x023294B0>
    >>> b = B()
    >>> # utilisation hors "classe", mais il faut bien passer le paramètre attendu 
    >>> zz(b)
    B
    >>> # on colle zz dans B
    >>> B.f = zz
    >>> b.f()
    B
    >>> # nettoyage
    >>> delattr(B, 'f')
    >>> b.f()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'B' object has no attribute 'f'
    >>>
    Voyez vous d'autres écueils ? Par exemple si je change la classe d'une instance, va-t'elle récupérer les classes parentes également ?
    Le gros écueil est qu'on ne repasse pas par le constructeur: l'instance ressemblera à un A sans avoir tous les attributs d'un A... et les abus risquent de d'être cauchemardesques côté maintenance et "effets de bords".

    Plus généralement, on crée l'instance X d'un B.
    X devra avoir le comportement d'un B.

    Bien sûr on peut se donner le droit de changer d'avis.
    Mais pour que tous les objets qui dépendent de X "s'adaptent" à n'importe quel changement... il faut limiter "n'importe quoi" en s'assurant que le nombre d'objets qui dépendent de X soit petit et "sous contrôle" - on sait ce qu'ils attendent de X.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  9. #9
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 062
    Par défaut
    Modifier une classe à partir de son instance, c'est comme transformer le patron à partir de l'objet lui même.

    C'est pas logique, je vais pas péter l'objet à coup de marteaux pour en refaire le dessin technique de l'objet.

    J'ai dû mal comprendre quelquechose...


  10. #10
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    Mais ici aussi j'ai l'impression qu'il y a plus simple (existe-t'il un moyen de transformer A.f en une "unbound fonction" qui ne vérifie pas la classe de son argument self ?).
    en utilisant le decorator staticmethod :

    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
    29
    30
    31
    32
    33
    34
    35
    36
    >>> class Foo(object):
            @staticmethod
    	def type(obj):
    		print type(obj)
     
     
    >>> a=Foo()
    >>> Foo.type(56)
    <type 'int'>
    >>> Foo.type(a)
    <class '__main__.Foo'>
    >>> a.type()
     
    Traceback (most recent call last):
      File "<pyshell#80>", line 1, in <module>
        a.type()
    TypeError: type() takes exactly 1 argument (0 given)
    >>> class Foo(object):
    	def _type_deco(s,func):
    		def wrapper():
    			return func(s)
    		return wrapper
     
    	def __init__(s):
    		s.type = s._type_deco(Foo.type)
     
            @staticmethod
    	def type(obj):
    		print type(obj)
     
     
    >>> a=Foo()
    >>> a.type()
    <class '__main__.Foo'>
    >>> Foo.type(56)
    <type 'int'>

  11. #11
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    Citation Envoyé par VV33D Voir le message
    Un autre exemple d'utilisation me vient à l'esprit. Je veux appliquer une méthode A.f() à un objet qui n'est pas une instance de A. J'ai une erreur si je fais A.f(objet_b), que je peux éviter en changeant temporairement la classe de objet_b.

    Mais ici aussi j'ai l'impression qu'il y a plus simple (existe-t'il un moyen de transformer A.f en une "unbound fonction" qui ne vérifie pas la classe de son argument self ?).
    Pour info, ça marche très bien en python3 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class A:
        def test(self):
            print(self.__class__)
     
    A.test(25) # <class 'int'>

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 29/08/2006, 12h01
  2. Réponses: 3
    Dernier message: 31/08/2005, 17h52
  3. Comment changer dynamiquement la valeur d'une option de DbGrid ?
    Par Atrebate62 dans le forum Composants VCL
    Réponses: 4
    Dernier message: 17/03/2005, 13h35
  4. [tomcat]chargement dynamique de classes depuis une webapp
    Par alphamax dans le forum Tomcat et TomEE
    Réponses: 2
    Dernier message: 12/03/2004, 09h59

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