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 :

Problème Py 3.11 je n'arrive pas à faire un str.replace pour une varialbe self.x


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    Novembre 2022
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Novembre 2022
    Messages : 3
    Par défaut Problème Py 3.11 je n'arrive pas à faire un str.replace pour une varialbe self.x
    Bonjour,

    Python 3.11 (distribution winpython) sous WIndows 10

    Dans l'exemple joint, je n'arrive pas à comprendre comment arriver à assigner une valeur à une variable d'un objet.
    J'ai le même fonctionnement que ce soit dans une "dataclass" ou une classe standard.

    La dataclass contient une serie de date. Quand ces dates sont lues, elles sont au format ISO avec un 'T' comme séparateur date - temps.
    Je souhaite simplement remplacer ce 'T' par un ' ' (espace) et j'utilise la fonction replace.
    Le problème c'est que dans boucle qui lit mes dates, le replace n'est pas pris en compte.


    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
     
    import datetime
    from dataclasses import dataclass,field
     
     
    @dataclass(slots=True)  # ! cela veut dire que pas de __dict__ dans les instances !!!
     
    class DacCols:
     
        compte:   str
        datecomptable: str
        datevaleur:    str
        reference:     str
        opdate: str
     
        valid: bool = field(init=False,compare=False)
     
        def __post_init__(self):
     
            self.valid = True
            self.validate_fields()
     
        def validate_fields(self):
            """validation des champs sauvés dans la dataclass"""
     
            for thisdate in (self.datevaleur,self.opdate,self.datecomptable):
     
                if thisdate is self.datevaleur: pr = True
                else: pr = False
     
                if pr: print(f'START:{thisdate} --- {thisdate is self.datevaleur} --- {type(thisdate)} --- {id(thisdate)}')
     
                if 'T' in thisdate: # remp
                    if pr: print(f'AVANT:{thisdate} --- {thisdate is self.datevaleur} --- {type(thisdate)} --- {id(thisdate)}')
     
                    thisdate = thisdate.replace('T',' ')
     
                    if pr: print(f'APRES:{thisdate} --- {thisdate is self.datevaleur} --- {type(thisdate)} --- {id(thisdate)}')
     
            self.datevaleur = self.datevaleur.replace('T',' ')
            print(f'APRESTOUT:{self.datevaleur} --- {self.datevaleur is self.datevaleur} --- {type(self.datevaleur)} --- {id(self.datevaleur)}')
     
            print("OUT:",self.datevaleur,self.opdate,self.datecomptable)
     
    class StdCols:
     
        def __init__(self,compte='', datecomptable='', datevaleur='', reference='', opdate=''):
     
            self.compte = compte
            self.datecomptable = datecomptable
            self.datevaleur = datevaleur
            self.reference = reference
            self.opdate = opdate
            self.valid = False
     
            self.validate_fields()
     
        def validate_fields(self):
            """validation des champs sauvés dans la dataclass"""
     
            for thisdate in (self.datevaleur, self.opdate, self.datecomptable):
     
                if thisdate is self.datevaleur:
                    pr = True
                else:
                    pr = False
     
                if pr: print(f'START:{thisdate} --- {thisdate is self.datevaleur} --- {type(thisdate)} --- {id(thisdate)}')
     
                if 'T' in thisdate:  # remp
                    if pr: print(
                        f'AVANT:{thisdate} --- {thisdate is self.datevaleur} --- {type(thisdate)} --- {id(thisdate)}')
     
                    thisdate = thisdate.replace('T', ' ')
     
                    if pr: print(
                        f'APRES:{thisdate} --- {thisdate is self.datevaleur} --- {type(thisdate)} --- {id(thisdate)}')
     
            self.datevaleur = self.datevaleur.replace('T', ' ')
            print(
                f'APRESTOUT:{self.datevaleur} --- {self.datevaleur is self.datevaleur} --- {type(self.datevaleur)} --- {id(self.datevaleur)}')
     
            print("OUT:", self.datevaleur, self.opdate, self.datecomptable)
            # map(lambda D: D.replace('T' , ' '), (self.datevaleur, self.opdate, self.datecomptable))
            # print("OUT:", self.datevaleur, self.opdate, self.datecomptable)
     
     
    def main():
     
        DAC = DacCols(compte='XXXXXXX', datecomptable='2021-05-07T00:00:00.000',
                      datevaleur='2021-05-01T00:00:00.000',
                      reference='2021-00008',
                      opdate='2021-05-12T00:00:00.000')
     
        print(DAC)
        CLA = StdCols(compte='XXXXXXX', datecomptable='2021-05-07T00:00:00.000',
                      datevaleur='2021-05-01T00:00:00.000',
                      reference='2021-00008',
                      opdate='2021-05-12T00:00:00.000')
     
        print(CLA)
     
    if __name__ == '__main__':
        main()
    # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Sortie complète :

    ///// dataclass
    START:2021-05-01T00:00:00.000 --- True --- <class 'str'> --- 2163923333520
    AVANT:2021-05-01T00:00:00.000 --- True --- <class 'str'> --- 2163923333520
    APRES:2021-05-01 00:00:00.000 --- False --- <class 'str'> --- 2163926942704
    APRESTOUT:2021-05-01 00:00:00.000 --- True --- <class 'str'> --- 2163926942464
    OUT: 2021-05-01 00:00:00.000 2021-05-12T00:00:00.000 2021-05-07T00:00:00.000
    DacCols(compte='XXXXXXX', datecomptable='2021-05-07T00:00:00.000', datevaleur='2021-05-01 00:00:00.000', reference='2021-00008', opdate='2021-05-12T00:00:00.000', valid=True)

    ////////résultats avec utilisation classe "normale"
    START:2021-05-01T00:00:00.000 --- True --- <class 'str'> --- 2163923333520
    AVANT:2021-05-01T00:00:00.000 --- True --- <class 'str'> --- 2163923333520
    APRES:2021-05-01 00:00:00.000 --- False --- <class 'str'> --- 2163926942704
    APRESTOUT:2021-05-01 00:00:00.000 --- True --- <class 'str'> --- 2163926943584
    OUT: 2021-05-01 00:00:00.000 2021-05-12T00:00:00.000 2021-05-07T00:00:00.000
    <__main__.StdCols object at 0x000001F7D3E26A90>
    # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Quelques explications....

    Quand je fais tourner ce code, aucune des dates dans la boucle n'est modifiée.
    Voici les différents 'print': (je ne prends qu'une date pour les explications).

    START:2021-05-01T00:00:00.000 --- True --- <class 'str'> --- 2489041465744
    AVANT:2021-05-01T00:00:00.000 --- True --- <class 'str'> --- 2489041465744
    APRES:2021-05-01 00:00:00.000 --- False --- <class 'str'> --- 2489045075568 #après le replace, ce n'est plus le même 'id'

    APRESTOUT:2021-05-01 00:00:00.000 --- True --- <class 'str'> --- 2489045075648 # ici je passe par self.date = self.date.replace('T','') et évidement cela fonctionne.

    OUT: 2021-05-01 00:00:00.000 2021-05-12T00:00:00.000 2021-05-07T00:00:00.000 # impression après la boucle -> le T reste pour les dates que je n'ai pas forcées.
    # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Pourquoi la boucle avec le replace() ne me donne pas le résultat voulu ? J'ai dû oublier quelquechose...


    Mais comment faire que ma boucle puisse appliquer le replace ? Qu'est-ce qui m'échappe ? Je comprends que comme l'id change, je n'ai pas le résultat voulu quand je fais thisdate = thisdate.replace ;coment faire pour que cela fonctionne ?
    Ma solution de contournement est simple, ne pas passer par une boucle mais modifier explicitement les dates. J'aimerais néanmoins comprendre pourquoi cela ne va pas dans une boucle ?

    Merci pour vos explications.
    Julio
    Fichiers attachés Fichiers attachés

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

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Bonjour
    J'ai téléchargé ton source. Déjà tu noteras que les règles indiquent qu'on préfère un code dans le post plutôt que d'avoir à le télécharger.
    Donc il ressort immédiatement un gros défaut: les attributs "compte", "datecomptable" et autres situés en dehors de toute méthode sont donc des attributs statiques. Ils s'appliquent à la classe et non à l'instance. Donc si une instance X positionne compte=X puis que plus tard une instance Y positionne compte=Y alors le compte (unique) sera à Y pour toute la classe (donc pour toutes les instances de classe). Peut-être que ton souci vient de là. Parce que depuis un exemple minimaliste...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class toto:
    	def __init__(self, v):
    		self.v=v
     
    	def replace(self, x, y):
    		self.v=self.v.replace(x, y)
     
    	def __str__(self):
    		return "v=[{}]".format(self.v)
     
    xxx=toto("Hello World")
    print(xxx)
    xxx.replace(" ", "+")
    print(xxx)
    ... le remplacement se fait parfaitement.

    PS: c'est quand-même malheureux de passer par un clone "winpython" alors que le Python originel est parfaitement disponible pour Windows. A chaque fois que les freedev sortent un truc valable, Microsoft s'arrange toujours pour se le récupérer et le redistribuer à sa sauce tout en y rajoutant des trucs qui font on ne sait quoi...
    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
    Futur Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    Novembre 2022
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Novembre 2022
    Messages : 3
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Bonjour
    J'ai téléchargé ton source. Déjà tu noteras que les règles indiquent qu'on préfère un code dans le post plutôt que d'avoir à le télécharger.
    Donc il ressort immédiatement un gros défaut: les attributs "compte", "datecomptable" et autres situés en dehors de toute méthode sont donc des attributs statiques. Ils s'appliquent à la classe et non à l'instance. Donc si une instance X positionne compte=X puis que plus tard une instance Y positionne compte=Y alors le compte (unique) sera à Y pour toute la classe (donc pour toutes les instances de classe). Peut-être que ton souci vient de là. Parce que depuis un exemple minimaliste...

    ... le remplacement se fait parfaitement.

    PS: c'est quand-même malheureux de passer par un clone "winpython" alors que le Python originel est parfaitement disponible pour Windows. A chaque fois que les freedev sortent un truc valable, Microsoft s'arrange toujours pour se le récupérer et le redistribuer à sa sauce tout en y rajoutant des trucs qui font on ne sait quoi...
    1. Ok pour le code. J'ai modifié mon post original.
    2. J'utilise une "dataclass" @dataclass() avant la définition de la classe et j'ai fait le même exemple avec une classe "classique". J'ai le même problème dans la boucle ou je fais les replace. Il est certain que si je mets explicitement self.date = self.date.replace(), cela fonctionne. Dans la boucle je fais v = self.date,v = v.replace() et cela n'affecte pas self.date.
    3. winpython : c'est pas un clone (rien à voir avec microsoft). Il s'agit d'une distribution qui me permet d'avoir la plupart des modules dont j'ai besoin (panda,pyexcel,numpy,etc...). Je pourrais aussi utiliser Anaconda. winpython : http://winpython.github.io/.

    Merci pour cette aide en tout cas.

    Cordialement.
    Julio

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

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par kpx57 Voir le message
    Dans la boucle je fais v = self.date,v = v.replace() et cela n'affecte pas self.date.
    Ah ben oui. J'avais pas remarqué ce détail mais maintenant que tu le mentionnes ça devient évident. Tu travailles dans la copie de self.date donc il n'y a aucune raison que self.date soit mise à jour. Si j'écris a=10; b=a; b+=15 il n'y a aucune raison que ça touche "a".
    On entre là dans une histoire de mutabilité et immuabilité des objets. En Python, les objets simples (str, int, float) et certains objets complexes (tuple) sont immuables. Ils ne possèdent pas de méthode interne permettant de les modifier. Modifier un int (un str) revient à réécrire un nouvel int (nouveau str) et à remplacer l'ancien par le nouveau.
    De là, si un de ces objets a été copié avant modif (avant remplacement), son remplacement ne touche pas la copie.
    Les autres (tous les autres) sont mutables. Ils possèdent des méthodes qui, quand elles sont appelées, les modifient.

    Comme la copie d'un objet ne se fait que par référence, pour les objets immuables cela n'a pas d'impact. On copie a dans b, puis on remplace a par autre chose (car c'est ce qui se passe en réalité quand on veut le modifier) cela n'impacte pas b.
    Mais pour les objets mutables, l'action de modification par méthode interne de l'un se répercute aussi sur l'autre (puisqu'en fait la copie et l'original tapent tous deux vers le même objet).
    Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> a=[1, 2, 3]
    >>> b=a
    >>> a.append("toto")
    >>> a
    [1, 2, 3, 'toto']
    >>> b
    [1, 2, 3, 'toto']
    >> hex(id(a))
    '0x7f5f80f3c070'
    >> hex(id(b))
    '0x7f5f80f3c070'
    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]

  5. #5
    Futur Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    Novembre 2022
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : Novembre 2022
    Messages : 3
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Ah ben oui. J'avais pas remarqué ce détail mais maintenant que tu le mentionnes ça devient évident. Tu travailles dans la copie de self.date donc il n'y a aucune raison que self.date soit mise à jour. Si j'écris a=10; b=a; b+=15 il n'y a aucune raison que ça touche "a".
    On entre là dans une histoire de mutabilité et immuabilité des objets. En Python, les objets simples (str, int, float) et certains objets complexes (tuple) sont immuables. Si on les copie et qu'on modifie la copie, l'original reste inchangé (immuable).
    D'autres (tous les autres) sont mutables. La copie ne se fait que par référence. Modifier ensuite la copie se répercute sur l'original (puisqu'en fait la copie et l'original tapent tous deux vers le même objet)
    Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> a=[1, 2, 3]
    >>> b=a
    >>> a.append("toto")
    >>> a
    [1, 2, 3, 'toto']
    >>> b
    [1, 2, 3, 'toto']
    >> hex(id(a))
    '0x7f5f80f3c070'
    >> hex(id(b))
    '0x7f5f80f3c070'
    OK, merci beaucoup. Comme tu dis c'est une question de commutativité et mutabilité.
    Je résume :

    AVANT:2021-05-01T00:00:00.000 --- True --- <class 'str'> --- 2163923333520 >>>> pointe vers la même adresse forvar = self.date
    APRES:2021-05-01 00:00:00.000 --- False --- <class 'str'> --- 2163926942704 >>>> après le replace(), forvar = self.date.replace() pointe vers une autre adresse et comme tu dis ne modifie pas le self.date. Je ne peux donc pas travailler de cette façon dans la boucle.

    """Remember that .replace() never modifies the original string; it returns a new string with the result of the operation.""" new string = nouvelle adresse (et pas by reference)

    Je m'endormirai un peu moins bête ce soir .
    Merci beaucoup pour l'aide.

    Cordialement.
    Julio

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

Discussions similaires

  1. [4.x] je n'arrive pas à faire fonctionner symfony 4 sur une Machine ubuntu18.4
    Par MathieuDelgado dans le forum Symfony
    Réponses: 9
    Dernier message: 10/06/2019, 16h52
  2. [Spip] simple problème de require que je n'arrive pas à résoudre
    Par beegees dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 2
    Dernier message: 04/12/2013, 10h01
  3. Réponses: 1
    Dernier message: 26/12/2012, 09h41
  4. Problème un peu bête mais j'arrive pas a comprendre.
    Par mckilleron dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 15/09/2010, 11h33
  5. Réponses: 1
    Dernier message: 12/02/2007, 15h22

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