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 :

Formater la valeur d'un attribut d'instance [Python 3.X]


Sujet :

Python

  1. #1
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Par défaut Formater la valeur d'un attribut d'instance
    Veuillez m'excuser, le titre n'est pas clair, mais je ne sais pas explique mon problème en une courte phrase.
    Voici une maquette d'un programme de conversion d'unités (entières mais non flottantes)
    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
    class Teste(object):
        def Aller(x):
            return round(x/257)
        def Retour(x):
            return x*257
        def __init__(self,x):
            self.x=x
        def conversion(self):
            y=Teste.Aller(self.x)
            self.x=y
            return y
        def conversionInv(self):
            y=Teste.Retour(self.x)
            self.x=y
            return y
    Je le teste et voici ce que j'obtiens:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> a=Teste(10652)
    >>> a.x
    10652
    >>> a.conversion()
    41
    >>> a.conversionInv()
    10537
    >>> a.conversion()
    41
    >>>
    Il est clair que la présence de round(x/257) ne me permets pas de revenir à la valeur première de a.x ( 10537 au lieu de 10652).
    Y-a-t'il un moyen de travailler en interne de la classe en flottant, afin de garder la précision suffisante pour revenir à la valeur initiale,
    mais de faire en sorte que a.x soit un entier lors de l'interrogation?
    Sis autrement, y-a-t'il un moyen de formater le résultat d'une interrogation style a.x?
    Dans mon cas, les calculs internes se faisant en flottant et le résultat a.x devra être un entier.

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 840
    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 840
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Cemalatowilo Voir le message
    Y-a-t'il un moyen de travailler en interne de la classe en flottant, afin de garder la précision suffisante pour revenir à la valeur initiale,
    mais de faire en sorte que a.x soit un entier lors de l'interrogation?
    Ben oui. Il te suffit de ne pas perdre le membre "x" défini dans __init__(). Donc dans toutes les méthodes où tu modifies self.x tu supprimes la ligne. Et tu n'affiches l'entier qu'au moment de l'interrogation. Eventuellement si vraiment tu veux que print(a.x) affiche une valeur déformée de x (parce que c'est ça que tu veux en réalité, afficher une valeur déformée de la chose stockée) alors tu rends "x" privé (tu remplaces self.x par self.__x) et tu crées un getter nommé "x" qui renvoie ce que tu veux. Un getter est une fonction qui a une syntaxe de membre (l'appelant ne sait pas qu'il appelle une fonction mais toi, dans ta fonction, tu fais ce que tu veux)

    Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Teste(object):
    	# Getter
    	x=property(lambda self: round(self.__x/257))
    	y=property(lambda self: round(self.__x ** 2))
     
    	def __init__(self,x):
    		self.__x=x
    a=Teste(10652)
    print(a.x)
    print(a.y)

    [edit]W a émis la même idée toutefois au lieu de mettre deux underscores, il n'en a mis qu'un seul. Dans ce cas, le membre "_x" n'est pas privé (on peut y accéder de l'extérieur de façon classique) mais il est privé "par convention" c'est à dire que les dev Python savent qu'il ne faut pas y toucher sauf si vraiment on ne peut pas faire autrement.
    Donc avec son exemple tu peux toujours récupérer la valeur non déformée de la data. Et il a utilisé une syntaxe plus classique pour faire son getter tandis que moi j'ai utilisé la syntaxe "raccourcie".
    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
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    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 762
    Par défaut
    Salut,

    Il y a 4 faces sur cette pièce.
    • La représentation interne des nombre.
    • Le formatage à leur appliquer pour les afficher sous la forme d'un tableau ou autre.
    • Le contrôle qu'on peut avoir sur l'interpréteur Python la dessus (les '>>>')
    • L'utilisation un peu opportuniste des classes que montre votre code.


    Citation Envoyé par Cemalatowilo Voir le message
    Y-a-t'il un moyen de travailler en interne de la classe en flottant, afin de garder la précision suffisante pour revenir à la valeur initiale,
    mais de faire en sorte que a.x soit un entier lors de l'interrogation?
    Yes!
    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 __init__(self, x):
    ...        self._x = x
    ...    @property
    ...    def x(self):
    ...        return int(self._x)
    ...
    >>> a = A(12.34)
    >>> a.x
    12
    >>> a._x
    12.34
    >>>
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Bonjour

    Ben oui. Il te suffit de ne pas perdre le membre "x" défini dans __init__(). Donc dans toutes les méthodes où tu modifies self.x tu supprimes la ligne. Et tu n'affiches l'entier qu'au moment de l'interrogation. Eventuellement si vraiment tu veux que print(a.x) affiche une valeur déformée de x (parce que c'est ça que tu veux en réalité, afficher une valeur déformée de la chose stockée) alors tu rends "x" privé (tu remplaces self.x par self.__x) et tu crées un getter nommé "x" qui renvoie ce que tu veux. Un getter est une fonction qui a une syntaxe de membre (l'appelant ne sait pas qu'il appelle une fonction mais toi, dans ta fonction, tu fais ce que tu veux)

    Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Teste(object):
    	# Getter
    	x=property(lambda self: round(self.__x/257))
    	y=property(lambda self: round(self.__x ** 2))
     
    	def __init__(self,x):
    		self.__x=x
    a=Teste(10652)
    print(a.x)
    print(a.y)

    [edit]W a émis la même idée toutefois au lieu de mettre deux underscores, il n'en a mis qu'un seul. Dans ce cas, le membre "_x" n'est pas privé (on peut y accéder de l'extérieur de façon classique) mais il est privé "par convention" c'est à dire que les dev Python savent qu'il ne faut pas y toucher sauf si vraiment on ne peut pas faire autrement.
    Donc avec son exemple tu peux toujours récupérer la valeur non déformée de la data. Et il a utilisé une syntaxe plus classique pour faire son getter tandis que moi j'ai utilisé la syntaxe "raccourcie".
    Curieux je n'ai que la première partie de ta réponse (jusqu'à ...au moment de l'interrogation.)
    Merci pour les explication, je vais les tester.

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 840
    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 840
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Cemalatowilo Voir le message
    Curieux je n'ai que la première partie de ta réponse (jusqu'à ...au moment de l'interrogation.)
    Quand tu cites un intervenant qui, lui-même, citait quelqu'un d'autre, tu ne récupères que la réponse de l'intervenant proprement dite. La "sous-citation" est squeezée dans ta réponse.
    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 762
    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 762
    Par défaut
    Citation Envoyé par Cemalatowilo Voir le message
    Y-a-t'il un moyen de travailler en interne de la classe en flottant, afin de garder la précision suffisante pour revenir à la valeur initiale,
    mais de faire en sorte que a.x soit un entier lors de l'interrogation?
    Sis autrement, y-a-t'il un moyen de formater le résultat d'une interrogation style a.x?
    Dans mon cas, les calculs internes se faisant en flottant et le résultat a.x devra être un entier.
    Plus sérieusement, si on fait avec ce que vous devriez connaître:
    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
    >>> class Teste(object):
    ...     def __init__(self,x):
    ...         self.x = x
    ...     def conversion(self):
    ...         self.x = self.x * 257
    ...         return int(self.x)
    ...     def conversionInv(self):
    ...         self.x = round(self.x / 257)
    ...         return int(self.x)
    ...
    >>> a = Teste(12.34)
    >>> a.conversion()
    3171
    >>> a.x
    3171.38
    >>> a.conversionInv()
    12
    >>> a.x
    12
    >>>
    note: a.conversionInv() ne récupère pas le 12.34 de départ à cause du "round".

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

  7. #7
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Par défaut
    Désolé, mais je ne m'en sors pas.
    Ta réponse ne correspond pas à ma demande, où alors je n'ai rien compris.
    je voudrais que y=round(xf=__x/257) me redonne __x, quand j'applique xf*257, xf étant la valeur en flottant de y.
    Merci de modifier mon code pour que je puisse comprendre.
    J'ai regardé la doc sur property(fget=None, fset=None,fdel=Nose,doc=None).
    Je ne sais pas où mettre les fonctions Aller(x) et Retour(x), dans fget ou fset?

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 840
    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 840
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Cemalatowilo Voir le message
    Ta réponse ne correspond pas à ma demande, où alors je n'ai rien compris.
    je voudrais que y=round(xf=__x/257) me redonne __x, quand j'applique xf*257, xf étant la valeur en flottant de y.
    Tu ne peux pas. Le round() fait perdre de la valeur au nombre. C'est quand-même pas compliqué à comprendre ça. Si tu fais un arrondi de 19/7 tu obtiens 2 mais 20/7 donne aussi 2. Alors comment ensuite avec 2 (le résultat) et 7 (le diviseur) tu peux retrouver le nombre d'origine (19 ou 20 dans mon exemple) ???
    Tu ne dois pas modifier le x initial si tu veux pouvoir le retrouver plus tard.

    Citation Envoyé par Cemalatowilo Voir le message
    J'ai regardé la doc sur property(fget=None, fset=None,fdel=Nose,doc=None).
    Je ne sais pas où mettre les fonctions Aller(x) et Retour(x), dans fget ou fset?
    T'occupe pas de property pour le moment. Fais-toi des méthodes spécifiques (ex def v1(self): return ..., def v2(self): return ...) et utilise-les pour afficher ce qui t'intéresse quand ça t'intéresse (ex print(a.v1()) ou print(a.v2())).
    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]

  9. #9
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Par défaut
    Je pense que j'ai mal posé mon problème, mais en discutant avec vous je me suis débloqué.
    Seul on a tendance à tourner en rond.
    En fait je veux créer un programme de conversion des valeurs rvb, tsl, hexa4 (4bits), hexa8 (8bits), rvb 4 et 8 bits d'une couleur entre elles.
    J'ai adapté le programme exposé dans le $5.1 page 198 du livre "Python par l'exemple" de A. Martelli, A.M. Ravenscroft & D. Ascher, collection O'Reilly.
    J'ai résolu mon problème en utilisant une variable self._rvb qui garde la précision pour que je puisse récupérer les mêmes valeurs entières entre toutes les conversions.
    voici ce que j'obtiens:
    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
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    # -*- coding:utf-8 -*-        
    class Couleur(object):
        '''
        Classe définissant des instances permettant d'avoir les équivalences
        entre les valeurs rvb4 (4bits), rvb8 (8bits), tsl, hexa4, hexa8.
        
        Ce programme est adapté de celui exposé $5.1 page 198 du livre "Python par
        l'exemple" de A. Martelli, A.M. Ravenscroft & D. Ascher, collection
        O'Reilly.
     
        Le principe est que l'attribut central est rvb. A chaque demande ou création
        d'une autre propriété, celle ci est calculée à la volée.
        Pour se faire les méthodes internes __getattr__ et __setattr__ sont
        redéfinies.
        L'explosion combinatoire des fonctions nécessaires pour convertir
        une propriété en une autre est ainsi évitée.
     
        Les données d'entrées sont vérifiées:
                            0<=r,v,b entiers<=255 ou 65535
                            0<=t entier<=360
                          0.<=s flottant<=1.
                          0.<=l flottant<=1.
                hexa string commençant par # et dont les
                caractères autorisés sont 0à9 et a,b,c,d,e,f
     
    >>> c=Couleur(rvb4=(56,110,89))
    >>> c
    (56,110,89)
    >>> print(c)
    rvb=(56, 110, 89)
    >>> c.tsl
    (157, 0.3253, 0.32549)
    >>> c.hexa4
    '#386e6e'
    >>> c.hexa8
    '#38386e6e5959'
    >>> c.rvb8
    (14392, 28270, 22873)
    >>> c.rvb4
    (56, 110, 89)
    >>> c.tsl=(67,.89,.56)
    >>> c.rvb4
    (219, 243, 43)
    >>> c.rvb8
    (56375, 62363, 11036)
    >>> c.tsl
    (67, 0.89, 0.56)
    '''
     
        tupleRVB=('Rouge','Vert','Bleu')
        tupleTSL=('Teinte','Saturation','Luminosité')
     
        def rvbrvb4(rvb):
            '''
            Retourne les valeurs de rvb sous forme d'entier
            '''
            return round(rvb[0]),round(rvb[1]),round(rvb[2])
     
        def rvb4rvb(rvb):
            return (rvb[0],rvb[1],rvb[2])
     
        def verifRvb4(rvb):
            """
            Vérifie que l'attibut d'instance self._rvb donné possède bien les bons
            types de variables rouge, vert et bleu qui sont des int compris entre
            0 et 255.
            """
            for i in range(0,3):
    #            if type(rvb[i]) is not int:
    #               raise TypeError("Valeur {0} doit être un entier pour la couleur {1}".format(rvb[i],Couleur.tupleRVB[i]))
                if rvb[i]<0 or rvb[i]>255:
                    raise ValueError('Valeur {0} incorrecte pour la couleur {1}'.format(rvb[i],Couleur.tupleRVB[i]))
     
        def rvbrvb8(rvb):
            """
            Retourne les valeurs rvb4 d'une couleur à partir de ses valeurs rvb8.
                                   0<=r4,v4,b4<=255
                                   0<=r8,v8,b8<=65535
            """
            return round(rvb[0]*257),round(rvb[1]*257),round(rvb[2]*257)
     
        def rvb8rvb(rvb):
            """
            Retourne les valeurs rvb8 d'une couleur à partir de ses valeurs rvb4.
                                   0<=r4,v4,b4<=255
                                   0<=r8,v8,b8<=65535
            """
            return rvb[0]/257,rvb[1]/257,rvb[2]/257
     
        def verifRvb8(rvb):
            """
            Vérifie que l'attibut d'instance self._rvb donné possède bien les bons
            types de variables rouge, vert et bleu qui sont des int compris entre
            0 et 65535.
            """
            for i in range(0,3):
                if type(rvb[i]) is not int:
                    raise TypeError("Valeur {0} doit être un entier pour la couleur {1}".format(rvb[i],Couleur.tupleRVB[i]))
                if rvb[i]<0 or rvb[i]>65535:
                    raise ValueError('Valeur {0} incorrecte pour la couleur {1}'.format(rvb[i],Couleur.tupleRVB[i]))
     
        def rvbhexa4(rvb):
            """
            Retourne la valeur héxadécimales (hexa) d'une couleur
            à partir de ses valeurs rvb.
                             0<=r,v,b<=255
            """
            r,v,b=round(rvb[0]),round(rvb[1]),round(rvb[1])
            return f"#{r:0>2x}{v:0>2x}{b:0>2x}"
     
        def hexa4rvb(val):
            """
            Retourne les valeurs rvb (rouge, vert, bleu) d'une couleur
            à partir de sa valeur héxadécimale (hexa).
            0<=r,v,b<=255
            """
            val = val.lstrip('#')
            lv = len(val)
            return tuple(int(val[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))
     
        def verifHexa4(val):
            """
            Vérifie que valeur est bien une valeur de couleur en hexadécimal
            """
            if val[0]!='#':
                raise ValueError('Premier caractère {0} incorrect: doit être "#"'.format(val[0]))
            if len(val)!=7:
                raise ValueError('len({0})!=7'.format(valeur))
            for i in range(1,7):
                if val[i] not in '0123456789abcdef':
                    raise ValueError("{0} n'est pas une valeur de couleur correcte en hexadécimale".format(val))
     
        def rvbhexa8(rvb):
            """
            Retourne la valeur héxadécimales (hexa) d'une couleur
            à partir de ses valeurs rvb8.
                             0<=r,v,b<=65535
            """
            r,v,b=Couleur.rvbrvb8(rvb)
            return f"#{r:0>4x}{v:0>4x}{b:0>4x}"
     
        def hexa8rvb(val):
            """
            Retourne les valeurs rvb4 (rouge, vert, bleu) d'une couleur
            à partir de sa valeur héxadécimale sur 8 bits (hexa8).
                                0<=r,v,b<=255
            """
            val = val.lstrip('#')
            lv = len(val)
            c=tuple(int(val[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))
            return (c[0]/257,c[1]/257,c[2]/257)
     
        def verifHexa8(val):
            """
            Vérifie que valeur est bien une valeur de couleur en hexadécimal
            """
            if val[0]!='#':
                raise ValueError('Premier caractère {0} incorrect: doit être "#"'.format(val[0]))
            if len(val)!=13:
                raise ValueError('len({0})!=13'.format(valeur))
            for i in range(1,13):
                if val[i] not in '0123456789abcdef':
                    raise ValueError("{0} n'est pas une valeur de couleur correcte en hexadécimale".format(val))
     
        def rvbtsl(rvb):
            """
            Retourne les valeurs tsl (teinte, saturation, luminance) d'une couleur
            à partir de ses valeurs RVB.
                                   0<=r,v,b<=255
                        0<=t<=360    0.<=s<=1.   0.<=l<=1.
            """
            R,V,B=rvb[0],rvb[1],rvb[2]
            M=max(R,V,B)
            m=min(R,V,B)
            chroma=M-m
            if chroma==0:
                t=0
            elif M==R:
                t=(((V-B)/chroma)%6)*60
            elif M==V:
                t=((2+(B-R)/chroma)%6)*60
            elif M==B:
                t=((4+(R-V)/chroma)%6)*60
            L=(m+M)/2/255
            if L==0: s=0.
            elif L==1: s=0.
            else: s=chroma/(1-abs(2*L-1))/255     
            return(round(t),round(s,5),round(L,5))
     
        def tslrvb(tsl=(0,0,0)):
            """
            Retourne les valeurs rvb (rouge, vert, bleu) d'une couleur
            à partir de ses valeurs tsl.
                               0<=r,v,b<=255
                      0<=t<=360  0.<=s<=1.  0.<=l<=1.
            """
            t,s,l=tsl[0],tsl[1],tsl[2]
            chroma=(1-abs(2*l-1))*s
            tp=t/60
            x=chroma*(1-abs(tp%2-1))
            if t==0:
                r,v,b=(0,0,0)
            elif 0<=tp and tp<1:
                r,v,b=Chroma,x,0
            elif 1<=tp and tp<2:
                r,v,b=x,chroma,0
            elif 2<=tp and tp<=3:
                r,v,b=0,chroma,x
            elif 3<=tp and tp<4:
                r,v,b=0,x,chroma
            elif 4<=tp and tp<5:
                r,v,b=x,0,chroma
            elif 5<=tp and tp<6:
                r,v,b=chroma,0,x
            m=l-chroma/2
            r,v,b=(r+m)*255,(v+m)*255,(b+m)*255         
            return (r,v,b)
     
        def verifTsl(val):
            """
            Vérifie que le tupple val est constitué de 3 entier ou flottants
            le premier doit être compris entre 0 et 360 (la teinte)
            les 2 derniers compris entre 0 et 1 (la saturation et la luminance)
            """
            for i in range(3):
                if type(val[i]) is not int and type(val[i]) is not float:
                    raise TypeError("Valeur {0} doit être un entier ou un flottant pour la {1}".format(val[0],
                                                                                                       Couleur.tupleTSL[0]))
            if val[0]<0 or val[0]>=360:
                raise ValueError('Valeur {0} incorrecte pour la {1}'.format(val[0],Couleur.tupleTSL[0]))
            for i in range(1,3):
                if val[i]<0 or val[i]>1:
                    raise ValueError('Valeur {0} incorrecte pour couleur {1}'.format(val[i],Couleur.tupleTSL[i]))
     
        fonctions={'rvb4':(rvbrvb4,rvb4rvb,verifRvb4),
                   'rvb8':(rvbrvb8,rvb8rvb,verifRvb8),
                   'hexa4':(rvbhexa4,hexa4rvb,verifHexa4),
                   'hexa8':(rvbhexa8,hexa8rvb,verifHexa8),
                   'tsl':(rvbtsl,tslrvb,verifTsl)}
     
        def __init__(self,**mots):
            try:
                nom,valeur=mots.popitem()
            except KeyError:
                nom,valeur='_rvb',(0,0,0)
            if mots or nom not in ['_rvb','rvb4','rvb8','hexa4','hexa8','tsl','pantome','tkinter','ral','francais']:
                mots[nom]=valeur
                raise TypeError('Paramètres incorrects {0}'.format(mots))
            setattr(self,nom,valeur)
     
        def __getattr__(self,nom):
            try:
                return Couleur.fonctions[nom][0](self._rvb)
            except KeyError:
                raise AttributError(nom)
     
        def __setattr__(self,nom,valeur):
            if nom in ['rvb4','rvb8','hexa4','hexa8','tsl','pantome','tkinter','ral','francais']:
                Couleur.fonctions[nom][2](valeur)
                self._rvb=Couleur.fonctions[nom][1](valeur)
            elif nom=='_rvb': # Pb d'appel récursif à __setattr__ si ce teste est absent
                Couleur.verifRvb4(valeur)
                object.__setattr__(self,nom,valeur)
            else:
                raise AttributError(nom)
     
        def __str__(self):
            c=round(self._rvb[0]),round(self._rvb[1]),round(self._rvb[2])
            return f"rvb={(c[0],c[1],c[2])}"
        def __repr__(self):
            c=round(self._rvb[0]),round(self._rvb[1]),round(self._rvb[2])
            return f"({c[0]},{c[1]},{c[2]})"
    J'aimerai connaître votre avis: est ce que je pouvais faire mieux, plus pythonique?
    Merci de votre temps.

  10. #10
    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
    Salut

    Oui il y a pas mal de piste d'amélioration.

    - Quand tu parcours les éléments d'une liste ou d'une chaine de caractère, tu n'as pas besoin de passer par l'indice
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    chaine='abcd'
    for i in range(len(x)):
        print(chaine[i])
    devient directement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for lettre in chaine :
        print(lettre)

    - Tu peux utiliser assert pour faire tes vérifications

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def verifHexa4(val):
                """
                Vérifie que valeur est bien une valeur de couleur en hexadécimal
                """
                assert( val[0]=='#'),'Premier caractère {0} incorrect: doit être "#"'.format(val[0])
                assert( len(val)==7),'len({0})!=7'.format(val)
                for v in val:
                    assert( v in '0123456789abcdef'),"{0} n'est pas une valeur de couleur correcte en hexadécimale".format(val)
    - Tu peux regrouper tout les codes de conversion en une sous-classe Conversion, et tout les codes de vérification en une sous-classe Vérification

    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
    class Couleur(object):
        class Conversion(object):
               def rvbrvb4(...) : 
                       ...
     
               ###  etc, on met toutes les méthodes de Conversion
     
        class Vérification(object):
               def verifRvb4(...) : 
                       ...
     
               ###  etc, on met toutes les méthodes de Vérification
     
        fonctions={'rvb4':(Conversion.rvbrvb4,Conversion.rvb4rvb,Verif.verifRvb4),
                   'rvb8':(Conversion.rvbrvb8,Conversion.rvb8rvb,Verif.verifRvb8),
                   'hexa4':(Conversion.rvbhexa4,Conversion.hexa4rvb,Verif.verifHexa4),
                   'hexa8':(Conversion.rvbhexa8,Conversion.hexa8rvb,Verif.verifHexa8),
                   'tsl':(Conversion.rvbtsl,Conversion.tslrvb,Verif.verifTsl)}
     
        def __init__(self, **mots):
             ...
     
        ### etc, le reste du code de la classe
    - Plutôt que de faire le point ci dessus, le mieux serait d'utiliser l'héritage de classe, mais les modifications sont plus lourdes. Le code deviendra cependant plus lisible et plus léger car tu aurais moins de méthode à écrire et tu aurais le passage de toutes les conversions (et pas seulement depuis, ou vers du rvb). Imagine que tu te mettes à rajouter du RVB_float, je te laisse calculer le nombre de méthode que ça te fait à rajouter. Au lieu de ça tu pourrais juste définir une classe mère, s'appuyant sur le type le plus précis. Puis dériver des classes traduisant juste ce type en fonction de la classe mère. Je te fais un exemple dans l'après midi si j'ai un peu de temps

  11. #11
    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
    Quelquechose dont le squelette serait ça :

    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
    class RVB_float(object): 
        def __init__(self, rvb_float):
            ### Verif rvb_float
            self.rvb_float = rvb_float
     
        @property
        def rvb4(self): 
            r = int(257*self.rvb_float[0])
            return tuple( int(round(257*canal)) for canal in self.rvb_float )
     
        @property
        def rvb8(self): 
            ### etc ...
            pass
     
    class RVB4(RVB_float):  
        def __init__(self, rvb4):
            ### verif rvb4 possible ici
            rvb_float = tuple( canal/257.0 for canal in rvb4 )
            super().__init__(rvb_float)
     
    class RVB8(RVB_float):  
        def __init__(self, rvb8):
            ### verif rvb8 possible ici
            rvb_float = tuple( canal/257.0**2 for canal in rvb8 )
            super().__init__(rvb_float)
     
     
    def MakeColor(**colordef):
        ### Methode alternative pour creer les couleurs
        assert(len(colordef)==1)
        print(colordef)
        defmode, defval = list(colordef.items())[0]
        assert(defmode in ('rvb_float', 'rvb4','rvb8','hexa4','hexa8','tsl'))
        classofinit = {'rvb_float': RVB_float, 
                        'rvb4': RVB4 ,
                        'rvb8': RVB8 ,
                        ### etc, les autres méthodes
                        }[defmode]
        return classofinit(defval)
     
    c = RVB8((14392, 28270, 22873))
    print(c.rvb_float)
    print(c.rvb4)  ###  (56, 110, 89)
     
    c2 = MakeColor(rvb8 = (14392, 28270, 22873))
    print(c2.rvb4)
    Là je défini une couleur en rvb8 par exemple. Et je demande ce qu'elle vaut en rvb4 alors que je n'ai pas écrit dans mon la conversion rvb8->rvb4. A vous de le compléter !

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

    Citation Envoyé par Cemalatowilo Voir le message
    En fait je veux créer un programme de conversion des valeurs rvb, tsl, hexa4 (4bits), hexa8 (8bits), rvb 4 et 8 bits d'une couleur entre elles.
    L'idée de garder une donnée de référence et faire la conversion vers ou depuis cette donnée est ce qui fait passer la complexité du problème de O(N2) à O(N). Et elle est très utilisée dans toutes les structures réseaux.

    Si on a des conversions homogènes entre les représentations 4 bits, entre les représentations 8bits sûr que quand on passe de 4 à 8 (et réciproquement), il faut supprimer ou ajouter de l'information.

    Après, je regarde ce que d'autres ont fait sur le sujet sur Internet.
    Il existe même un module standard Python colorsys qui fait un peu çà.

    Mais surtout une bibliothèque externe colour qui fait déjà çà.
    Lecture en diagonale... pas mal.
    Voilà ce que vous devriez aller lire pour progresser.

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

  13. #13
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Par défaut
    Merci à vous deux lg_53 et wistricks pour votre temps.
    J'étudie toutes les infos que vous me fournissez, et il y en a beaucoup!
    J'espère pouvoir me les imprégner.
    A bientôt

  14. #14
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 840
    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 840
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Cemalatowilo Voir le message
    Merci à vous deux lg_53 et wistricks pour votre temps.
    Ouais, de rien.
    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]

  15. #15
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Par défaut
    Je viens de lire avec attention les remarques de lg_53. Je m'interroge.

    1) Il est indéniable que "assert" est moins moins verbeux que "raise". mais j'ai utilisé le second car il m'a semblé, en lisant la littérature sur python, que le premier était a utilisé pour du débogage de programme et que le second permettait de cibler les erreurs (ValueError, AttibutError, ...).
    Donc pour un programme au point, qu'est ce qui est plus pythonique: "assert" ou "raise"? ou est ce un choix personnel?

    2) Intérêt de la création des sous-classes conversion et vérification?
    J'ai l'impression que c'est plus une question de style de programmation. Mois qui suis un peu feneant du clavier, écrire "conversion." et "verification." devant chaque fonction me gonfle un peu.

    3) Intérêt également de créer l'héritage de classe? Je ne suis pas très à l'aise avec cette notion, et j'ai du mal a rentré dans l'exemple que tu m'as généreusement donné.
    Il semble que ce soit pour évite l'explosion combinatoire des programmes de conversion si l'on veut ajouter un attribut supplémentaire à la couleur.
    Ors dans le principe que j'utilise ce n'est pas le cas, car si j'ajoute par exemple l'attribut x, il ne faut créer que 3 fonctions supplémentaires: conversion de x vers _rvb, de _rvb vers x et la vérification de la saisie de x.
    En effet si je veux ensuite passer de x vers tsl, le programme se débrouille pour, à la volée, convertir x vers_rvb et _rvb vers tsl.

    Merci encore pour tes commentaires

  16. #16
    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 Cemalatowilo Voir le message
    1) Il est indéniable que "assert" est moins moins verbeux que "raise". mais j'ai utilisé le second car il m'a semblé, en lisant la littérature sur python, que le premier était a utilisé pour du débogage de programme et que le second permettait de cibler les erreurs (ValueError, AttibutError, ...).
    Donc pour un programme au point, qu'est ce qui est plus pythonique: "assert" ou "raise"? ou est ce un choix personnel?
    Je mentionnais assert, car je ne savais pas si vous aviiez connaissance de cette alternative qui réduit l'écriture. Effectivement dans votre cas le raise convient mieux. Ce n'est pas du tout lié au fait que votre programme soit au point ou pas. Pour résumé, raise permet de lever des exceptions (dont on peut préciser le type en plus) du à une mauvaise utilisation de la part de l'utilisateur. Assert, lui va permettre de mettre des contrôles, à certains endroits plus profond du code, pour aider le développeur. Il existe une option de compilation qui permet de ne pas exécuter ses instructions de contrôle pour accélérer le code.

    Citation Envoyé par Cemalatowilo Voir le message
    2) Intérêt de la création des sous-classes conversion et vérification?
    J'ai l'impression que c'est plus une question de style de programmation. Mois qui suis un peu feneant du clavier, écrire "conversion." et "verification." devant chaque fonction me gonfle un peu.
    Ca hiérarchise le code. Et croyez moi si vous l'enrichissez et qu'il continue à se rallonger, ca sera juste vital d'avoir classée les infos. Sinon votre code sera juste le gros bordel et même vous même vous ne vous y retrouverez plus ! Et justement, écrire "conversion." et "verification." devant chaque fonction vient du fait que vous raisonné en terme de fonctionnalité plutôt qu'en terme d'objet. En gros vous vous dites j'ai besoin d'une fonctionnalité de vérification, puis après vous vous demandez quelles sont les différents types de vérifications que vous voulez (rgb8, rgb16, etc ...). Et si justement vous faisiez l'inverse : Commencer par énumérer les types, puis après dans chaque type lui mettre sa vérifications (ainsi que c'est autre fonctionnalités). Et boum, vous avez là un objet, et il vous affranchi d'écrire des préfixes supplémentaires.
    Notez aussi que beaucoup d'IDE on aussi des petits systèmes pour plié/déplié le contenu d'une classe ou d'une fonction, pour également afficher la structure du code, ... et donc vous facilitez la navigation dans votre code.


    Citation Envoyé par Cemalatowilo Voir le message
    3) Intérêt également de créer l'héritage de classe? Je ne suis pas très à l'aise avec cette notion, et j'ai du mal a rentré dans l'exemple que tu m'as généreusement donné.
    Il semble que ce soit pour évite l'explosion combinatoire des programmes de conversion si l'on veut ajouter un attribut supplémentaire à la couleur.
    Ors dans le principe que j'utilise ce n'est pas le cas, car si j'ajoute par exemple l'attribut x, il ne faut créer que 3 fonctions supplémentaires: conversion de x vers _rvb, de _rvb vers x et la vérification de la saisie de x.
    En effet si je veux ensuite passer de x vers tsl, le programme se débrouille pour, à la volée, convertir x vers_rvb et _rvb vers tsl.
    Le programme se débrouille .... oui mais comment ? C'est une brique que vous implémentez encore par vous même ? Là c'est python que le fait. Donc c'est du code que primo vous n'écrivez pas, et qui secondo est à priori plus fiable que ce que vous et moi pourrions écrire. Dans votre cas il faut créer 3 fonctions supplémentaires. Avec la solution des sous-classes, il en faut 3 aussi, mais vous aller devoir toucher à chacune des sous classe. Avec la solution d'une classe par type, et bien vous rajouter juste la classe de ce nouveau type, avec ses 3 fonctions, et vous ne toucher pas aux autres classes existantes (ce qui en terme d'intégrité du code est quand même vachement mieux). Et imaginez que ce nouveau type est qqch d'un peu particulier qui nécéssite une fonction de plus par exemple, et bien là ca se ferait tout naturellement dans cette classe. Dans les autres implémentation, ca ferait forcément qqch de bancal.

    Prenez le temps de regarder la solution que je vous propose, elle fonctionne telle quelle. Suffit d'y rajouter après les autres types dont vous avez besoin, sur le même modèle.

  17. #17
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Par défaut
    Merci de votre réponse, je commence à mieux comprendre les principes.
    Bon WE de fin de confinement

  18. #18
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 762
    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 762
    Par défaut
    Citation Envoyé par Cemalatowilo Voir le message
    J'ai l'impression que c'est plus une question de style de programmation.
    Vous mettez le doigt sur une bonne question: découper le tout en parties ne se fait pas d'une façon unique mais dépend de celui qui tient le couteau.

    Regardez la différence entre vos codes, lg_53 a une approche POO "orthodoxe". Vous avez choisi d'utiliser des fonctionnalités "python" (getattr, setattr) pour dispatcher l'appel aux différentes fonctions.

    Les deux points de vue se défendent.

    Et si vous avez du temps et le courage de farfouiller ces questions, vous verrez que des tas de "pontes" de la communauté Python racontent pourquoi la POO orthodoxe ne fait pas trop sens avec Python.

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

  19. #19
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Par défaut
    Je pense avoir compris le principe.
    Voici le code auquel j'arrive:
    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
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    # -*- coding:utf-8 -*-def RVBtoTSL(rvb=(0,0,0)):
     
    def RVBtoTSL(rvb=(0,0,0)):
        """
        Retourne les valeurs tsl (teinte, saturation, luminance) d'une couleur
        à partir de ses valeurs RVB.
                               0<=r,v,b<=255
                    0<=t<=360    0.<=s<=1.   0.<=l<=1.
        """
        R,V,B=rvb[0],rvb[1],rvb[2]
        M=max(R,V,B)
        m=min(R,V,B)
        chroma=M-m
        if chroma==0: t=0
        elif M==R: t=(((V-B)/chroma)%6)*60
        elif M==V: t=((2+(B-R)/chroma)%6)*60
        elif M==B: t=((4+(R-V)/chroma)%6)*60
        L=(m+M)/2/255
        if L==0: s=0.
        elif L==1: s=0.
        else: s=chroma/(1-abs(2*L-1))/255     
        return(round(t),s,L)
     
    def TSLtoRVB(tsl=(0,0,0)):
        """
        Retourne les valeurs rvb (rouge, vert, bleu) d'une couleur
        à partir de ses valeurs tsl.
                           0<=r,v,b<=255
                  0<=t<=360  0.<=s<=1.  0.<=l<=1.
        """
        t,s,l=tsl[0],tsl[1],tsl[2]
        chroma=(1-abs(2*l-1))*s
        tp=t/60
        x=chroma*(1-abs(tp%2-1))
        if t==0: r,v,b=(0,0,0)
        elif 0<=tp and tp<1: r,v,b=chroma,x,0
        elif 1<=tp and tp<2: r,v,b=x,chroma,0
        elif 2<=tp and tp<3: r,v,b=0,chroma,x
        elif 3<=tp and tp<4: r,v,b=0,x,chroma
        elif 4<=tp and tp<5: r,v,b=x,0,chroma
        elif 5<=tp and tp<6: r,v,b=chroma,0,x
        m=l-chroma/2
        r,v,b=(r+m)*255,(v+m)*255,(b+m)*255         
        return (r,v,b)
     
    class RVBfloat(object):
        def verif(val):
            for i in range(3):
                if rvb_float[i]<0 or rvb_float[i]>1.:
                    raise ValueError('Valeur {0} incorrecte pour la couleur {1}'.
                                     format(rvb[i],Couleur.tupleRVB[i]))        
        def __init__(self,rvb_float):
            self.rvb_float=rvb_float
     
        @property
        def rvb4(self):
            return tuple(int(round(257*i)) for i in self.rvb_float)
     
        @property
        def rvb8(self):
            return tuple(int(round(257*257*i)) for i in self.rvb_float)
     
        @property
        def hexa4(self):
            r,v,b=tuple(int(round(257*i)) for i in self.rvb_float)
            return f"#{r:0>2x}{v:0>2x}{b:0>2x}"
     
        @property
        def hexa8(self):
            r,v,b=tuple(int(round(257*257*i)) for i in self.rvb_float)
            return f"#{r:0>4x}{v:0>4x}{b:0>4x}"
     
        @property
        def tsl(self):
            rvb=tuple(int(round(257*i)) for i in self.rvb_float)
            t,s,l=RVBtoTSL(rvb)    
            return(round(t),round(s,5),round(l,5))
    #    @tsl.setter
    #    def tsl(self,tsl):
    #        self.rvbfloat=f(tsl)
    #        pass
     
    class RVB4(RVBfloat):
        def __init__(self,rvb4):
            """
            Vérifie que l'attibut d'instance self._rvb donné possède bien les bons
            types de variables rouge, vert et bleu qui sont des int compris entre
            0 et 255.
            """
            for i in range(0,3):
                if type(rvb4[i]) is not int:
                    raise TypeError("Valeur {0} du {1}ième nombre doit être un entier".format(rvb4[i],i))
                if rvb4[i]<0 or rvb4[i]>255:
                    raise ValueError('Valeur {0} du {1}ième nombre incorrecte'.format(rvb4[i],i))
     
            rvbfloat = tuple(i/257 for i in rvb4)
            super().__init__(rvbfloat)
     
    class RVB8(RVBfloat):
        def __init__(self,rvb8):
            """
            Vérifie que l'attibut d'instance self._rvb donné possède bien les bons
            types de variables rouge, vert et bleu qui sont des int compris entre
            0 et 65535.
            """
            for i in range(0,3):
                if type(rvb8[i]) is not int:
                    raise TypeError("Valeur {0} du {1}ième nombre doit être un entier".format(rvb8[i],i))
                if rvb8[i]<0 or rvb8[i]>65535:
                    raise ValueError('Valeur {0} du {1}ième nombre incorrecte'.format(rvb8[i],i))
     
            rvbfloat = tuple(i/257**2 for i in rvb8)
            super().__init__(rvbfloat)
     
    class HEXA4(RVBfloat):
        def __init__(self,hexa4):
            """
            Vérifie que valeur est bien une valeur de couleur en hexadécimal
            """
            if hexa4[0]!='#':
                raise ValueError('Premier caractère {0} incorrect: doit être "#"'.format(hexa4[0]))
            if len(hexa4)!=7:
                raise ValueError('len({0})!=7'.format(hexa4))
            for i in range(1,7):
                if hexa4[i] not in '0123456789abcdef':
                    raise ValueError("{0} n'est pas une valeur de couleur correcte en hexadécimale".format(hexa4))
     
            hexa4 = hexa4.lstrip('#')
            lv = len(hexa4)
            rvbfloat=tuple(int(hexa4[i:i + lv // 3], 16)/257 for i in range(0, lv, lv // 3))
            super().__init__(rvbfloat)
     
    class HEXA8(RVBfloat):
        def __init__(self,hexa8):
            """
            Vérifie que valeur est bien une valeur de couleur en hexadécimal
            """
            if hexa8[0]!='#':
                raise ValueError('Premier caractère {0} incorrect: doit être "#"'.format(hexa8[0]))
            if len(hexa8)!=13:
                raise ValueError('len({0})!=13'.format(hexa8))
            for i in range(1,13):
                if hexa8[i] not in '0123456789abcdef':
                    raise ValueError("{0} n'est pas une valeur de couleur correcte en hexadécimale".format(hexa8))
     
            hexa8 = hexa8.lstrip('#')
            lv = len(hexa8)
            rvbfloat=tuple(int(hexa8[i:i + lv // 3], 16)/257**2 for i in range(0, lv, lv // 3))
            super().__init__(rvbfloat)
     
    class TSL(RVBfloat):
        def __init__(self,tsl):
            """
            Vérifie que le tupple val est constitué de 3 entier ou flottants
            le premier doit être compris entre 0 et 360 (la teinte)
            les 2 derniers compris entre 0 et 1 (la saturation et la luminance)
            """
            for i in range(3):
                if type(tsl[i]) is not int and type(tsl[i]) is not float:
                    raise TypeError("Valeur {0} doit être un entier ou un flottant".format(tsl[0]))
            if tsl[0]<0 or tsl[0]>=360:
                raise ValueError('Valeur {0} incorrecte pour la teinte'.format(hexa8[0]))
            for i in range(1,3):
                if tsl[i]<0 or tsl[i]>1:
                    raise ValueError('Valeur {0} incorrecte pour le {1}ième nombre'.format(tsl[i],i))
     
            rvb=TSLtoRVB(tsl)
            rvbfloat=(rvb[0]/257,rvb[1]/257,rvb[2]/257)
            super().__init__(rvbfloat)
     
    def Couleur(**definition):
        nom,val=list(definition.items())[0]
        if nom not in ['rvbfloat','rvb4','rvb8','hexa4','hexa8','tsl']:
            raise ValueError()
        classe={'rvbfloat':RVBfloat,
                'rvb4':RVB4,
                'rvb8':RVB8,
                'hexa4':HEXA4,
                'hexa8':HEXA8,
                'tsl':TSL}[nom]
        return classe(val)
    C'est indéniable qu'il est beaucoup plus lisible que celui que j'avais initialement écrit.
    Mais son comportement ne correspond pas tout à fait à celui que j'ai écrit:
    Voici le comportement du nouveau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> c=Couleur(hexa4="#af67de")
    >>> c.tsl
    (276, 0.64324, 0.63725)
    >>> c.tsl=(89,.67,.54)
    Traceback (most recent call last):
      File "<pyshell#116>", line 1, in <module>
        c.tsl=(89,.67,.54)
    AttributeError: can't set attribute
    >>>
    Voici celui du mien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> c=Couleur(hexa4="#af67de")
    >>> c.tsl
    (276, 0.64324, 0.63725)
    >>> c.tsl=(89,.67,.54)
    >>> c.hexa4
    '#8cd83b'
    >>>
    Il n'y a pas de message d'erreur.
    Je pense que cela vient de l'absence de la méthode setter de property.
    Si c'est le cas il faut alors mettre dans chaque méthode de la classe RVBfloat la fonction inverse dans le setter de chaque property (j'ai écrit une maquette au niveau de la fonction tsl(self). C'est redondant avec ce qui est dans les autres classes.
    Une partie de l'avantage est perdue.
    Qu'en pensez vous?

  20. #20
    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
    C'est justement le principe de la classe. Ca vous interdit de faire c.tsl=(89,.67,.54), qui n'est pas une bonne pratique, car vous rompez l'intégrité de votre classe en faisant ça. Si le programmeur souhaite autoriser cette option à l'utilisateur alors il définit des setters. Mais dans votre cas vous n'en avez absolument pas besoin !

    Suffit juste d'écrire :
    au lieu de

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 20
    Dernier message: 23/03/2015, 17h41
  2. Réponses: 5
    Dernier message: 23/12/2010, 09h50
  3. [XSD] test de la valeur d'un attribut
    Par ka0z dans le forum Valider
    Réponses: 3
    Dernier message: 21/08/2005, 20h46
  4. Réponses: 2
    Dernier message: 07/07/2005, 18h11
  5. Valeur d'un attribut
    Par DarkMoox dans le forum Requêtes
    Réponses: 5
    Dernier message: 10/10/2004, 18h31

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