Variable locale qui change toute seule

Fermé
Karamazov0 Messages postés 12 Date d'inscription dimanche 16 août 2020 Statut Membre Dernière intervention 2 juillet 2023 - Modifié le 12 févr. 2021 à 16:17
Karamazov0 Messages postés 12 Date d'inscription dimanche 16 août 2020 Statut Membre Dernière intervention 2 juillet 2023 - 12 févr. 2021 à 22:02
Bonjour à tous,

Je souhaite programmer une fonction uparrow(B,S) qui prend en entrée deux ensembles S, B donnés sous forme de liste, et qui donne en sortie la collection [[S,B]]:=\{ K tels que S\cap B \subseteq K \subseteq S \cup B \}. Par exemple, dans le cas particulier où S \subseteq B, alors on demande l'ensemble des K tels que S \subseteq K \subseteq B. Les ensembles sont donnés sous forme de liste. Par exemple, uparrow([1],[1,2,3])=\{ [1],[1,2],[1,3],[1,2,3] \}. Autre exemple, uparrow([1,3],[2,3])=\{ [3],[1,3],[2,3],[1,2,3] \}. Voici l'illustration avec des patatoïdes:




Malheureusement, au lieu de uparrow([1],[1,2,3])=\{ [1],[1,2],[1,3],[1,2,3] \}, mon programme me donne ceci:



J'ai donc placé des print dans ma fonction uparrow pour voir exactement ce que fait le programme. Et là, j'ai eu la surprise de constater que ce que je pensais être une variable locale définie une bonne fois pour toutes, bb, changeait à l'intérieur de ma fonction def. En effet:



bb est censé prendre l'intersection B \cap S de B et S. C'est la fonction cap(B,S) qui le fait (voir ci-dessous)
tt est censé prendre l'union B \cup S de B et S. C'est la fonction cup(B,S) qui le fait (voir ci-dessous)
setminus(tt,bb) est l'opération tt \ bb, qui prend tous les éléments de tt qui ne sont pas dans bb.
La fonction dupsort() sert à éliminer les doublons et à mettre la liste dans l'ordre.
On veut donc prendre toutes les parties possibles de setminus(tt,bb) pour les ajouter à bb, de sorte que nous aurons bien ce que nous voulons.






Les fonction d'intersection (cap), d'union (cup) et de "privé de" (setminus) marchent bien. De même que la fonction qui donne toutes les parties d'un ensemble (je l'ai piochée sur internet et ça marche bien). La fonction dupsort() marche bien aussi.

Mon problème est donc que bb et tt changent ! Quelqu'un pourrait-il m'expliquer ce phénomène ? Un grand merci par avance,

Karamazov0.

Post-scriptum. Soit dit en passant, c'est une bizarrerie qui m'est arrivé plusieurs fois. J'ai l'impression que quand on écrit des choses comme a=b, Python ne considère pas seulement qu'on prend la valeur de b à un moment donné pour la mettre dans a, mais bien qu'on "attache la variable b à la variable a" (comme une identité mathématique), c'est-à-dire que quand on modifiera plus tard la valeur de b, cela modifiera automatiquement la valeur de a. Ce genre de chose ne devrait pas arriver, non ?

4 réponses

Utilisateur anonyme
12 févr. 2021 à 18:41
Bonjour

tout d'abord pour poster un code, il faut faire comme décrit là https://www.commentcamarche.net/infos/25899-demander-de-l-aide-pour-vos-exercices-sur-ccm/

En l'état, personne ne va s'embêter à tout retaper de son coté pour tester. Sans compter le risque d'erreur de transcription.


Ensuite

Ce genre de chose ne devrait pas arriver, non ?
ben en fait ça dépend des langages et/ou du "type" de l'affectation.
Je ne suis pas un spécialiste de python, donc je ne vais pas te dire si tu as raison ou pas sans pouvoir tester.


0
Karamazov0 Messages postés 12 Date d'inscription dimanche 16 août 2020 Statut Membre Dernière intervention 2 juillet 2023
12 févr. 2021 à 18:53
Bonjour Whismeril, merci pour ta réponse. Je ne peux plus modifier mon message (je pense qu'il y a un délais limite pour ça), donc je mets le code ci-dessous.


def partiesliste(seq):
    p = []
    i, imax = 0, 2**len(seq)-1
    while i <= imax:
        s = []
        j, jmax = 0, len(seq)-1
        while j <= jmax:
            if (i>>j)&1 == 1:
                s.append(seq[j])
            j += 1
        p.append(s)
        i += 1 
    return p

def dupsort(L):
    L=list(dict.fromkeys(L))
    L.sort()
    return L


def cap(S,T):
    capp=[]
    for k in S:
        if k in T:
            capp.append(k)
    return dupsort(capp)

def cup(S,T):
    cupp=S
    for k in T:
        cupp.append(k)
    return dupsort(cupp)

def setminus(S,T):
    setm=[]
    for k in S:
        if k not in T:
            setm.append(k)
    return dupsort(setm)


def uparrow(B,S):
    bb=dupsort(cap(B,S))
    print("bb=",bb)
    tt=dupsort(cup(B,S))
    print("tt=",tt)
    print("")
    PP=[]
    for kk in partiesliste(setminus(tt,bb)):
        PP.append(dupsort(cup(bb,kk)))
        print("bbboucle=",bb)
        print("ttboucle=",tt)
        print("PP=",PP)
        print("")
    return PP
    

0
yg_be Messages postés 23352 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 27 novembre 2024 1 554
12 févr. 2021 à 19:31
tu n'as pas mis comment appeler tes fonctions.
0
yg_be Messages postés 23352 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 27 novembre 2024 Ambassadeur 1 554
12 févr. 2021 à 19:13
bonjour,
je pense que tu aurais pu donner un exemple plus simple, basé sur ton post-scriptum.
par exemple ceci:
ascal=5
bscal=ascal
print(ascal,bscal)
ascal=6
print(ascal,bscal)
alist=[1,2,3]
blist=alist
clist=alist.copy()
print(alist,blist,clist)
alist[2]=4
print(alist,blist,clist)
0
yg_be Messages postés 23352 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 27 novembre 2024 1 554
12 févr. 2021 à 19:27
Le genre de chose qui ne devrait pas arriver, c'est de faire des suppositions basées sur des intuitions non vérifiées.
quand tu écris
a=b
, il est important de comprendre ce qu'est
a
.
tu imagines que a est une liste, alors que Python a décidé que
a
était une référence vers une liste.
tu copies donc la référence, et b est donc une autre référence vers la même liste.
la méthode
copy
que j'ai utilisée pour copier la liste (il y a d'autres techniques) copie la liste.
si la liste contient des listes (comme
[[1,2], 2]
), elle contient en fait des références, qui seront copiées.
il existe une méthode
deepcopy
, dans le package copy, qui fait une copie "profonde" de listes.
l'important, bien sûr, c'est de comprendre ce qu'on écrit, et ce que Python en fait.
d'autant plus délicat que Python ne permet pas de déclarer les types des variables, et que les variables peuvent changer de type à toute assigation.
0
yg_be Messages postés 23352 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 27 novembre 2024 1 554
Modifié le 12 févr. 2021 à 19:38
c'est probablement ta fonction
cup()
que tu devrais modifier, pour y faire
cupp=S.copy()
, afin de ne pas modifier la liste référée par le premier paramètre de la fonction,
S
.
0
Karamazov0 Messages postés 12 Date d'inscription dimanche 16 août 2020 Statut Membre Dernière intervention 2 juillet 2023 > yg_be Messages postés 23352 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 27 novembre 2024
12 févr. 2021 à 21:06
Magnifique yg_be, effectivement ça marche ! Bien vu; tu m'as rendu un grand service.
Mais du coup, c'est vraiment casse-pied que Python fasse ce genre de choses. (i) Est-ce qu'il n'y a pas un moyen de déclarer au début du programme que nous refusons les "références vers" ? (ii) Et au passage, est-ce que tu connais une bonne source, un document qui explique en détails cette question ?
Merci encore pour ton aide et ta gentillesse; bonne soirée,
Karamazov0.
0
yg_be Messages postés 23352 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 27 novembre 2024 1 554 > Karamazov0 Messages postés 12 Date d'inscription dimanche 16 août 2020 Statut Membre Dernière intervention 2 juillet 2023
12 févr. 2021 à 21:46
Je cherchais le mot adéquat: Python est très sympa, et, comme tu l'écris, "casse-pied".
Est-ce un bon choix de prendre pour collaborateur un casse-pied perpétuel?
A chacun de décider. Peut-être est-ce un bon choix tant que le résultat ne compte pas trop, tant qu'on veut s'amuser.
De nombreux autres langages sont plus explicites, plus rigoureux et moins surprenants. Moins sympas, aussi, plus de boulot, et moins populaires.
Il est totalement impossible de canaliser Python via des déclarations. Il faut se laisser séduire, ou le quitter.
Python contient tellement de pièges que je ne peux pas recommander une bonne source. Chaque piège est expliqué quelque part, on ne peut le découvrir qu'après avoir identifié le piège. Si tu avais compris que tu voulais copier une liste, tu aurais facilement trouvé via "python copier liste". Python t'a laissé imaginer que tu copiais une liste. Face à d'autres langages, tu te serais demandé "bon, je suis bloqué, comment puis-je copier une liste?".
0
Karamazov0 Messages postés 12 Date d'inscription dimanche 16 août 2020 Statut Membre Dernière intervention 2 juillet 2023
Modifié le 12 févr. 2021 à 22:05
Oui c'est vrai.... d'ailleurs Python m'a rendu bien des services, il suffit seulement de connaître le truc; mais il y a aussi la force de l'habitude... En tout cas, merci encore pour ton aide, c'était vraiment gentil de ta part.
0