[Problème] Fonction modifiant ses variables d'entrée??

Fermé
Liquid - Modifié le 7 août 2020 à 22:07
quent217 Messages postés 421 Date d'inscription vendredi 25 septembre 2015 Statut Membre Dernière intervention 1 mars 2024 - 8 août 2020 à 01:09
Bonjour à tous,

Je viens vers vous car je suis complétement bloqué face à un fonctionnement de python.
Le projet est assez complexe, donc pour vous éviter de devoir montrer le code, j'ai simulé simplement mon problème.
Voici le type de code qui me pose problème

def PLS(A):
B = A
B[0] = B[2]
return(B)

A = [1,2,3]
D = PLS(A)
print(A)


Si je fais tourner ce code, je m'attend à avoir D = [3,2,3] et A, non modifiée, égale à [1,2,3]
Pourtant, je me retrouve avec D = A = [3,2,3]

Pourquoi python modifie la variable d'entrée lorsque celle ci est appelée dans une fonction?
Et surtout, comment faire pour que A reste inchangée malgré avoir été appelée?


Je vous remercie pour votre aide, j'en ai vraiment besoin, cela fait des heures que je m'arrache les cheveux :D

2 réponses

quent217 Messages postés 421 Date d'inscription vendredi 25 septembre 2015 Statut Membre Dernière intervention 1 mars 2024 344
8 août 2020 à 00:21
Bonjour,
dans vos futurs messages, merci d'utiliser les balises de code : https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code

Votre problème vient du fait que en python, tous les arguments de fonctions sont passés par référence. (Enfin les objets mutables sont passés par références, et pour les objets non mutables ça ne change rien, donc on peut considérer que c'est toujours le cas)
Cela signifie que si vous modifiez un objet dans une fonction, ça modifiera aussi l'objet qui a été passé en paramètre car il s'agit du même objet.

Lorsque l'on fait une association tu type B = A, c'est la même chose, la copie se fait toujours par référence. A et B sont donc 2 noms qui référencent le même objet. C'est pour ça que lorsque vous modifez B, vous modifiez A en même temps car il s'agit du même objet.

Pour régler le problème, il faut demander explicitement à faire une copie de l'objet avant de le modifier.
B = A.copy()
# ou
B = A[:]

Faites attention notamment avec tableaux à plusieurs dimentions car c'est là une copie partielle qui est faite et non d'une copie profonde ! Pour faire une copie profonde vous pouvez faire
from copy import deepcopy
B = deepcopy(A)


Vous pouvez aussi faire la copie au moment de l'appelle de la fonction si vous le souhaitez
D = PLS(A.copy())


Bonne soirée
0
Merci beaucoup! Tout est clair maintenant.

Je n'ai juste pas compris cette histoire de copie partielle. Qu'entendez vous par là?
Je ne travaille actuellement qu'avec des listes de listes de listes (etc...) qui simulent donc des tableaux à plusieurs dimensions. Quel effet supplémentaire à l'effet deepcopy?

En tout cas je vous remercie pour le temps que vous m'avez accordé!
0
quent217 Messages postés 421 Date d'inscription vendredi 25 septembre 2015 Statut Membre Dernière intervention 1 mars 2024 344
8 août 2020 à 01:09
Lorsque vous avez une liste de listes, la liste principale contient des références faire les sous listes. Si vous faites une copie de la liste principale, la fonction copy va se contenter de copier chacune de références vers les listes qui la composent. Cela aura pour effet que si vous modifiez la copie du tableau, vous modifierez aussi le tableau d'origine.
Par exemple :
A = [
    [1, 2],
    [3, 4],
    [5, 6]
]

B = A.copy()
B[0][0] = 7
print(A[0][0]) # Output : 7


La fonction deepcopy permet de copier récursivement chacune des sous listes, et les sous-sous listes, etc.
dans mon exemple précédent, c'est comme si on faisait :
B = [A[0].copy(), A[1].copy(), A[2].copy()]


Ca permet d'éviter le problème précédent :
from copy import deepcopy

A = [
    [1, 2],
    [3, 4],
    [5, 6]
]

B = deepcopy(A)
B[0][0] = 7
print(A[0][0]) # Output : 1
0