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 :

Comment ça se passe ? Concaténation de chaînes


Sujet :

Python

  1. #1
    apt
    apt est déconnecté
    Membre régulier
    Inscrit en
    Mai 2002
    Messages
    867
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 867
    Points : 118
    Points
    118
    Par défaut Comment ça se passe ? Concaténation de chaînes
    Bonjour,

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    S = "Hello"
    S +=" World!"
    => Nom : new string +.png
Affichages : 384
Taille : 20,0 Ko

    Dans une concaténation de chaînes, comment se déroule le processus d'allocation de la nouvelle valeur en mémoire, sans effacer ni perdre le nom de la variable?

    La création de la nouvelle chaîne sera-t-elle enregistrée dans une variable temporaire avant de mettre à jour la valeur de S ?

    Merci d'avance.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Vous ne devez pas essayer de mélanger les différents niveaux d'abstractions, sinon vous allez juste vous perdre!

    Après si vous voulez voir ce qu'il se passe sous le capot, çà commence par:
    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
    >>> import dis
    >>> def f():
    ...     S = 'hello'
    ...     S += ' world'
    ...
    >>> dis.dis(f)
      2           0 LOAD_CONST               1 ('hello')
                  2 STORE_FAST               0 (S)
     
      3           4 LOAD_FAST                0 (S)
                  6 LOAD_CONST               2 (' world')
                  8 INPLACE_ADD
                 10 STORE_FAST               0 (S)
                 12 LOAD_CONST               0 (None)
                 14 RETURN_VALUE
    >>>
    et vous voyez que dans ce monde là, les choses du dessus se traduisent de façon bizarre.

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

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par apt Voir le message
    Dans une concaténation de chaînes, comment se déroule le processus d'allocation de la nouvelle valeur en mémoire, sans effacer ni perdre le nom de la variable?
    La création de la nouvelle chaîne sera-t-elle enregistrée dans une variable temporaire avant de mettre à jour la valeur de S ?
    Déjà il faut éclater les opérateurs qui mixent opération et affectation( typiquement +=, -= etc) car ils se décomposent ("+=" devient "=" puis "+").
    Ainsi s+="World" se traduit par s=s + "World". Donc Python commence par calculer s + "World" (méthode "__add__" de l'objet "str") puis place le résultat de cette opération dans "s".
    Ne te reste qu'à regarder le source de Python, chercher l'objet "str" puis décortiquer sa méthode "__add__".
    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]

  4. #4
    apt
    apt est déconnecté
    Membre régulier
    Inscrit en
    Mai 2002
    Messages
    867
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 867
    Points : 118
    Points
    118
    Par défaut
    Bonjour wiztricks, Sve@r,

    @wiztricks : pas compris cette liste ?

    @Sve@r : Est-ce que l'adresse mémoire du premier s (s = "Hello") et la même pour le deuxième s (s = "Hello World!") ?

    Merci.

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par apt Voir le message
    @Sve@r : Est-ce que l'adresse mémoire du premier s (s = "Hello") et la même pour le deuxième s (s = "Hello World!") ?
    Non. Lors de la nouvelle affectation, la mémoire précédente qui était dans le "s" est alors libérée. La nouvelle chaine est créée en mémoire puis affectée dans "s". Te suffit d'afficher hex(id(s)) à chaque étape et tu verras que les valeurs changent.

    Ensuite on peut mieux le voir si on crée son propre objet string qui montre ses étapes de création et de suppression...
    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
    15
    16
    17
    18
    19
    20
    #!/usr/bin/env python3
    # coding: utf-8
     
    class myStr(object):
    	def __init__(self, s):
    		print("__init__", repr(self), s)
    		self.__chaine=s
    	# __init__()
     
    	def __del__(self): print("__del__", repr(self), self.__chaine)
     
    	def __str__(self): return self.__chaine
     
    	def __add__(self, s): return myStr(self.__chaine+str(s))
    # class myStr
     
    s=myStr("Hello")
    print(s)
    s+=myStr("World")
    print(s)

    Déjà tu te rends compte que pour créer l'addition, je suis obligé de retourner un nouvel objet (sinon je ne pourrais pas écrire des expressions comme truc=myStr("a") + myStr("b")).

    Et donc au résultat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    __init__ <__main__.myStr object at 0x7f20c73a5860> Hello		# Première création
    Hello									# Affichage de la chaine "s"
    __init__ <__main__.myStr object at 0x7f20c73a54a8> World		# Seconde création
    __init__ <__main__.myStr object at 0x7f20c73a5470> HelloWorld		# Création du résultat de l'addition qui ira dans "s"
    __del__ <__main__.myStr object at 0x7f20c73a54a8> World			# Suppression de la seconde création devenue inutile
    __del__ <__main__.myStr object at 0x7f20c73a5860> Hello			# Suppression de la première création devenue inutile (puisque "s" est libérée)
    HelloWorld								# Affichage de la nouvelle chaine "s"
    __del__ <__main__.myStr object at 0x7f20c73a5470> HelloWorld		# Suppression du résultat de l'addition devenu inutile (puisque "s" est de nouveau libérée)
    Si on change juste s+=myStr("World") par ss=s+myStr("World") (donc on ne perd plus le premier "s"), le résultat...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    __init__ <__main__.myStr object at 0x7f5b4ec8a828> Hello		# Première création
    Hello									# Affichage de la chaine "s"
    __init__ <__main__.myStr object at 0x7f5b4ec8a470> World		# Seconde création
    __init__ <__main__.myStr object at 0x7f5b4ec8a400> HelloWorld		# Création du résultat de l'addition qui ira cettte fois dans "ss"
    __del__ <__main__.myStr object at 0x7f5b4ec8a470> World			# Suppression de la seconde création devenue inutile
    HelloWorld								# Affichage de la nouvelle chaine "ss"
    __del__ <__main__.myStr object at 0x7f5b4ec8a828> Hello			# Suppression de la première création devenue inutile (puisque "s" est libérée)
    __del__ <__main__.myStr object at 0x7f5b4ec8a400> HelloWorld		# Suppression du résultat de l'addition devenu inutile (puisque "ss" est libérée)
    ... et on voit que le premier "s" n'est supprimé qu'à la fin du programme. Maintenant... est-ce vraiment utile???

    Sinon un truc que là je pense bien plus important: les valeurs par défaut des paramètres d'une fonction qui sont crées non pas quand la fonction est appelée, mais quand la fonction est implémentée.

    Un exemple
    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
    15
    16
    #!/usr/bin/env python3
    # coding: utf-8
     
    class myObject(object):
    	def __init__(self): print("__init__", repr(self))
    	def __del__(self): print("__del__", repr(self))
    # class myObject
     
    def fct(n=myObject()):
    	print("entrée dans fct ", n)
     
    print(1)
    fct(123)
    print(2)
    fct()
    print(3)

    Et le résultat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    __init__ <__main__.myObject object at 0x7fae6ae55828>		# L'objet est créé avant même que la fonction soit appelée
    1								# Affichage témoin
    entrée dans fct  123						# La fonction a été appelée avec un vrai paramètre, elle l'affiche
    2								# Affichage témoin
    entrée dans fct  <__main__.myObject object at 0x7fae6ae55828>	# La fonction a été appelée sans paramètre, elle affiche alors le paramètre par défaut créé au début du programme
    3								# Affichage témoin
    __del__ <__main__.myObject object at 0x7fae6ae55828>		# L'objet est supprimé avec la fonction quand le programme se termine
    C'est pour cela que ce genre de fonction...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def f(n, tab=[]):
    	tab.append(n)
    	return tab
    # f()
     
    print(f(1))
    print(f(2))
    print(f(3))
    ... peut causer des surprises...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    [1]
    [1, 2]
    [1, 2, 3]
    !!!
    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 sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par apt Voir le message
    @wiztricks : pas compris cette liste ?
    Quelle liste?

    On n'arrivera pas à vous expliquer quoi que ce soit si vous n'avez pas le minimum de bases pour comprendre.

    Il serait plus simple d'essayer d'expliquer quel problème vous cherchez à résoudre ou pourquoi vous posez cette question.

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

  7. #7
    apt
    apt est déconnecté
    Membre régulier
    Inscrit en
    Mai 2002
    Messages
    867
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 867
    Points : 118
    Points
    118
    Par défaut
    Citation Envoyé par wiztricks
    Quelle liste?

    Celle-ci :


    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
    >>> import dis
    >>> def f():
    ...     S = 'hello'
    ...     S += ' world'
    ...
    >>> dis.dis(f)
      2           0 LOAD_CONST               1 ('hello')
                  2 STORE_FAST               0 (S)
     
      3           4 LOAD_FAST                0 (S)
                  6 LOAD_CONST               2 (' world')
                  8 INPLACE_ADD
                 10 STORE_FAST               0 (S)
                 12 LOAD_CONST               0 (None)
                 14 RETURN_VALUE 
    >>>

    Citation Envoyé par wiztricks
    pourquoi vous posez cette question.

    j'aimerais savoir comment python traite une concaténation (les étapes).


    Par exemple, utilise-t-il une nouvelle variable pour construire la nouvelle chaîne, avant de retourner la chaîne finale?


    La variable s pour cette chaine finale, est-ce la même que la chaîne de départ ou une nouvelle variable s ?


    La case mémoire allouée en premier temps pour la chaine "Hello", est-elle la même case mémoire pour la chaine "Hello World!"

    Sve@r

    Merci pour la démonstration, je vais essayer de comprendre tout ça !

  8. #8
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    Règle numéro 1: Il n'y a pas de variable en Python.

    Lorsque tu fais s = "Hello" Python construit un objet str avec la valeur "Hello". Ensuite, si l'opération n'a pas échoué, il colle une étiquette avec la mention "s" sur cet objet.

    Donc l'objet c'est la str et non pas l'étiquette.

    La variable en tant que "boîte dont le contenu peut varier" est une notion totalement fausse en Python et tes questionnements reposent semble-t-il sur cette erreur.

    Si tu ajoutes s = "Bonjour" Python construit un objet str avec la valeur "Bonjour". Ensuite se souvient avoir déjà fait une étiquette avec un "s", l'enlève de l'objet str("Hello") et la colle sur le nouvel objet. Et lorsque tu fais une concaténation c'est pareil, tu construis un nouvel objet, dans une nouvelle zone mémoire mais c'est l'ancienne étiquette qui est réutilisée.

    Un même objet peut recevoir autant d'étiquettes que l'on veut. L'objet lui-même possède un compteur de référence pour gérer cela, lorsque ce compteur arrive à zéro il est effacé par un mécanisme appelé "Garbage collector". La mémoire libérée n'est pas nécessairement restituée au système, ça c'est de la cuisine interne.

    Ceci dit, ça ne dérange pas d'utiliser le terme variable, on comprend ce que tu veux dire, l'erreur est de voir ce "s" comme un objet ou une case mémoire.

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Pour compléter ce qu'a raconté VinsS.
    C'est quoi une variable en Python l'association d'une chaîne de caractères (le nom de la variable) avec un objet.
    Et Python réalise cette association via des dictionnaires (au moins pour les variables globales):

    Je définis la clef X dans le dictionnaire globals()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    >>> globals()['X'] = 123
    Et si j'accède à X "normalement", je retrouve mes petits:
    Et la réciproque est vraie...
    J'assigne à X un autre objet:
    Et si je regarde le côté dictionnaire de la chose, je retrouve l'objet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> globals()['X']
    'abc'
    >>>
    Voilà comment fonctionne Python... Et vou voyez que comprenant cela, vos questions n'ont pas trop de sens.

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

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Ce qu'il est intéressant de noter, c'est que toute copie d'un objet se contente en fait de copier juste l'étiquette...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> a=12345
    >>> id(a)
    140561597757136
    >>> b=a
    >>> id(b)
    140561597757136
    ... jusqu'à ce qu'il y ait nouvelle affectation dans l'étiquette...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> b=12345
    >>> id(b)
    140561597757168
    Et dans ce cas, la valeur de la nouvelle affectation (ici identique à l'ancienne) n'entre même pas en ligne de compte (sinon cela voudrait dire que Python va "chercher" si "par hasard" la valeur "12345" n'a pas déjà été stockée quelque part ce qui n'apporterait aucune plus-value à l'opération).

    Et ce comportement (à l'économie) fait que la copie d'un objet (même super gros) ou son envoi à une fonction est super rapide
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >> a=list(range(10000*5000))			# Ca ça prendra un peu de temps
    >>> id(a)
    140561597454280
    >>> b=a						# Ca ce sera instantané
    >>> id(b)
    140561597454280

    L'inconvénient c'est que comme il n'y a en réalité qu'un seul objet, modifier l'original se répercute dans la copie
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> a=[1, 2, 3]
    >>> b=a
    >>> a.append("xxx")
    >>> b
    [1, 2, 3, 'xxx']

    Toutefois il s'agit là d'un inconvénient assez minime car d'une part cela convient dans 99% des cas (il est assez rare de travailler sur deux objets similaires en parallèle). Mais si cela arrive, alors il est tout à fait possible de "forcer" la copie
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> a=[1, 2, 3]
    >>> b=list(a)
    >>> a.append("xxx")
    >>> b
    [1, 2, 3]

    Après, les concaténations de chaines ne sont qu'un cas particulier de ce comportement général.
    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]

Discussions similaires

  1. Réponses: 0
    Dernier message: 10/10/2016, 10h31
  2. Réponses: 3
    Dernier message: 19/09/2010, 03h50
  3. comment concaténer plusieurs chaînes de caractères
    Par saih_tam dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 11/02/2009, 11h42
  4. Comment concaténer des chaînes issues d'un fichier ini ?
    Par Neit_Sabes dans le forum Framework .NET
    Réponses: 10
    Dernier message: 27/09/2006, 09h28
  5. [XSLT 1.0] Concaténation de chaînes
    Par tofita_49 dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 25/07/2005, 18h34

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