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 :

Quelle méthode est appelée lors du print d'une classe ?


Sujet :

Python

Vue hybride

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

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut Quelle méthode est appelée lors du print d'une classe ?
    Bonjour à tous

    Petite question (j'ère sur la toile depuis pas mal de temps et je ne trouve pas la moindre piste ...) : Lorsque j'ai une classe, quelle méthode est appelée lorsque je print cette classe ? Je dit bien la classe (et pas une instance de cette classe).

    Le but serait de faire qqch comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def MakeClass(clsname):
        class Class():
             name = clsname
     
        return Class
     
    X = MakeClass('X')
    print(X)
    mais où print(X) me renverrai qqch contenant le nom donné en paramètre de la factory (ici 'X'), plutôt que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <class '__main__.MakeClass.<locals>.Class'>
    qui ne permet pas de faire la différence entre 2 classes différentes fabriquées avec cette même factory.

    J'ai vu des choses comme ca aussi sur la toile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def MakeClass(clsname):
        class Class(): pass
     
        Class.__name__ = clsname
        return Class
     
    X = MakeClass('X')
    print(X)
    mais bon à part définir un nouvel attribut (que ce soit name ou __name__) ça ne change manifestement pas grand chose puisque lorsqu'on fait print(X) ces attributs ne semblent pas utilisés.

    Merci

    Bonne journée

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par lg_53 Voir le message
    J'ai vu des choses comme ca aussi sur la toile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def MakeClass(clsname):
        class Class(): pass
     
        Class.__name__ = clsname
        return Class
     
    X = MakeClass('X')
    print(X)
    mais bon à part définir un nouvel attribut (que ce soit name ou __name__) ça ne change manifestement pas grand chose puisque lorsqu'on fait print(X) ces attributs ne semblent pas utilisés.
    En utilisant cet exemple, ça marche si tu fais print(X.__name__). Sinon moi non plus je n'y arrive pas.
    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]

  3. #3
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    ça marche si tu fais print(X.__name__)
    Ca c'est sûr ! Mais ça ne répond pas forcément au besoin.
    Moi je me dis qu'il doit bien avoir une méthode, à la manière de __str__ mais pour la classe, méthode que je pourrais surcharger... mais impossible de savoir ce qu'il y a derrière ça

  4. #4
    Membre chevronné
    Homme Profil pro
    BTS SN IR
    Inscrit en
    Mai 2017
    Messages
    514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : BTS SN IR

    Informations forums :
    Inscription : Mai 2017
    Messages : 514
    Par défaut
    Il y a str et repr:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >>> class A:
    	def __str__(self): return "str"
    	def __repr__(self): return "repr"
     
     
    >>> A() # retourne le rep
    repr
    >>> print(A()) # retourne le str
    str
    >>> f"{A()}" # retourne str
    'str'
    >>> f"{A()!r}" # retourne repr
    'repr'
    edit: lu un peu vite la question
    tu peux toujours utiliser qualname

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> class B: pass
     
    >>> B.__qualname__ = "foo"
    >>> B
    <class '__main__.foo'>

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Merci les gars !

    Citation Envoyé par flapili Voir le message
    edit: lu un peu vite la question
    tu peux toujours utiliser qualname
    Oui je m'en doutais que qqn tomberait dans ce panneau , c'est pour ça que dans mon 1er post j'ai bien précisé

    Citation Envoyé par lg_53
    Je dit bien la classe (et pas une instance de cette classe)
    mais bon t'es entièrement pardonné puisque __qualname__ fournit une solution.

    Ceci dit je ne sais pas si c'est très bon de toucher à ça, donc j'examine aussi la solution de Wiztricks.

    Premier script auquel j'aboutis après des lectures sur les métaclasses qui m'ont bien instruites.
    Je regarde aussi ce que donne la __mro__, ainsi que la représentation d'une instance pour voir.

    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 MetaType(type):
        def __repr__(self):
            return super().__repr__().replace('NewClass',self.name)
     
    def MakeClass(clsname):
        class NewClass(metaclass=MetaType):
            name = clsname
     
            def __repr__(self):  ### For instance of X
                return super().__repr__().replace('NewClass',self.name)
     
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### OK
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### OK
    Là je tape sur un attribut "maison" nommé name. Je me dis du coup, pourquoi ne pas redéfinir __name__ de la même manière ?

    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 MetaType(type):
        def __repr__(self):
            return super().__repr__().replace('NewClass',self.__name__)
     
    def MakeClass(clsname): 
        class NewClass(metaclass=MetaType):
            __name__ = clsname
     
            def __repr__(self):  ### For instance of X
                return super().__repr__().replace('NewClass',self.__name__)
     
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### KO
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### KO
    Là ça ne fonctionne plus. Mais j'avais trouvé des personnes qui avait mis cette définition en dehors de la classe, après coup, peut être que ça change qqch :
    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
    class MetaType(type):
        def __repr__(self):
            return super().__repr__().replace('NewClass',self.__name__)
     
    def MakeClass(clsname): 
        class NewClass(metaclass=MetaType):
            def __repr__(self):  ### For instance of X
                return super().__repr__().replace('NewClass',self.__class__.__name__)
     
        NewClass.__name__ = clsname
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### OK
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### OK
    Alors oui ça change qqch, car là ça produit le résultat escompté ! Là je ne comprends pas pourquoi ...
    Par contre si je tape sur __qualname__, là je peux le définir où je veux ça ne change rien :

    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
    def MakeClass(clsname): 
        class NewClass():
            pass
     
    #    NewClass.__qualname__ = clsname
        NewClass.__qualname__ = NewClass.__qualname__.replace('NewClass',clsname)
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### OK
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### OK
     
    def MakeClass(clsname): 
        class NewClass():
    #        __qualname__ = clsname
            __qualname__ = __qualname__.replace('NewClass',clsname)
     
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### OK
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### OK
    et je peux même au passage m'affranchir de la définition de __repr__ pour les instances de NewClass.

    Pour essayer de voir ce qui se passe de différent entre __name__ et __qualname__, j'essaie d'intercepter les attributs de classer demandé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
    class MetaType(type):
        def __getattribute__(self, name):
            if name != '__class__' :
                print('Get... ', name)
            return super().__getattribute__(name)
     
    def MakeClass(clsname): 
        class Class(metaclass=MetaType7):
              pass
     
        return Class
     
     
    X = MakeClass('X')
    print(X)
    print(X())
    print('qualname : ',X.__qualname__)
    print(X.__mro__)
    Là on voit que printer X appelle __qualname__ !
    De même printer on voit que printer X.__mro__ appelle __qualname__ !
    Et l'affichage d'uns instance de X, elle tire sur la __mro__, donc ça expliquerait pourquoi je n'ai plus besoin de surcharger __repr__ pour les instances, lorsque je modifie directement __qualname__.

    Donc ça explique une partie de mes interrogations. Par contre reste en suspend :
    Pourquoi mettre __name__ = ... dans la classe ne fait pas pareil que de le définir après coup en dehors de la classe ?

    Modifier __qualname__ me parait être la solution la plus simple et efficace, je ne parviens pas à trouve d'avantages à ta solution Wiztricks. Si tu en as, je suis preneur.

    Merci les gars pour ce bon aprem de réflexion sur le sujet que vous m'avez donné.


    Pour ceux qui veulent tester, je vous met tout les bout de code présentés ici en 1 seul bloc :

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    print('==========(1)===========')
    class MetaType(type):
        def __repr__(self):
            return super().__repr__().replace('NewClass',self.name)
     
    def MakeClass(clsname):
        class NewClass(metaclass=MetaType):
            name = clsname
     
            def __repr__(self):  ### For instance of X
                return super().__repr__().replace('NewClass',self.name)
     
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### OK
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### OK
     
    print('==========(2)===========')
    class MetaType(type):
        def __repr__(self):
            return super().__repr__().replace('NewClass',self.__name__)
     
    def MakeClass(clsname): 
        class NewClass(metaclass=MetaType):
            __name__ = clsname
     
            def __repr__(self):  ### For instance of X
                return super().__repr__().replace('NewClass',self.__name__)
     
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### KO
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### KO
     
     
    print('==========(3)===========')
    class MetaType(type):
        def __repr__(self):
            return super().__repr__().replace('NewClass',self.__name__)
     
    def MakeClass(clsname): 
        class NewClass(metaclass=MetaType):
            def __repr__(self):  ### For instance of X
                return super().__repr__().replace('NewClass',self.__class__.__name__)
     
        NewClass.__name__ = clsname
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### OK
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### OK
     
     
     
    print('==========(4)===========')
    def MakeClass(clsname): 
        class NewClass():
            pass
     
    #    NewClass.__qualname__ = clsname
        NewClass.__qualname__ = NewClass.__qualname__.replace('NewClass',clsname)
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### OK
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### OK
     
    print('==========(5)===========')
    def MakeClass(clsname): 
        class NewClass():
    #        __qualname__ = clsname
            __qualname__ = __qualname__.replace('NewClass',clsname)
     
        return NewClass
     
    X = MakeClass('XXXX')
    print(X)    ### OK
    print(X())  ### OK
    print('qualname : ',X.__qualname__)
    print(X.__mro__)  ### OK

  6. #6
    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,

    Citation Envoyé par lg_53 Voir le message
    Ceci dit je ne sais pas si c'est très bon de toucher à ça, donc j'examine aussi la solution de Wiztricks.
    J'ai proposé une solution à la question initiale:
    Lorsque j'ai une classe, quelle méthode est appelée lorsque je print cette classe ?
    Mais j'ai l'impression que la question est devenu comment fabriquer "dynamiquement" une classe avec le __name__ qu'on veut.
    Ma suggestion est: si on fabrique la classe "dynamiquement", on passe par type et pas par "class" machin qu'on rame à bricoler:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def MakeClass(name):
        return type(name, (), {})
     
    X = MakeClass('X')
    print(X)
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    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,

    Citation Envoyé par lg_53 Voir le message
    Lorsque j'ai une classe, quelle méthode est appelée lorsque je print cette classe ?
    Lorsqu'il s'agit d'une instance, c'est la méthode __str__ qui est appelée (si elle existe).
    Lorsqu'il s'agit d'une classe, ce sera la méthode __str__ de la metaclass (qui par défaut est "type"). Et pour changer çà, il faut fabriquer la class à partir d'une metaclass ou on définit son __str__.

    - 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. [PHP 5.3] Savoir quelle méthode est appelée via le constructeur
    Par Madfrix dans le forum Langage
    Réponses: 14
    Dernier message: 19/10/2010, 16h45
  2. Réponses: 0
    Dernier message: 08/09/2009, 18h34
  3. Réponses: 5
    Dernier message: 04/07/2006, 10h17
  4. [Copie de Fichier] Quelle méthode est la plus rapide ?
    Par n@n¤u dans le forum Entrée/Sortie
    Réponses: 16
    Dernier message: 04/05/2006, 13h59
  5. [VBA-PP]Quelle procédure est appelée au démarrage de PowerPoint
    Par jorge7281 dans le forum VBA PowerPoint
    Réponses: 11
    Dernier message: 27/04/2006, 17h31

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