Variable locale qui change toute seule

Signaler
Messages postés
7
Date d'inscription
dimanche 16 août 2020
Statut
Membre
Dernière intervention
12 février 2021
-
Messages postés
7
Date d'inscription
dimanche 16 août 2020
Statut
Membre
Dernière intervention
12 février 2021
-
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

Messages postés
15611
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
25 février 2021
665
Bonjour

tout d'abord pour poster un code, il faut faire comme décrit là https://www.commentcamarche.net/faq/10925-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.


Messages postés
7
Date d'inscription
dimanche 16 août 2020
Statut
Membre
Dernière intervention
12 février 2021

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
    

Messages postés
14315
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 février 2021
805
tu n'as pas mis comment appeler tes fonctions.
Messages postés
14315
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 février 2021
805
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)
Messages postés
14315
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 février 2021
805
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.
Messages postés
14315
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 février 2021
805
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
.
Messages postés
7
Date d'inscription
dimanche 16 août 2020
Statut
Membre
Dernière intervention
12 février 2021
>
Messages postés
14315
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 février 2021

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.
Messages postés
14315
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 février 2021
805 >
Messages postés
7
Date d'inscription
dimanche 16 août 2020
Statut
Membre
Dernière intervention
12 février 2021

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?".
Messages postés
7
Date d'inscription
dimanche 16 août 2020
Statut
Membre
Dernière intervention
12 février 2021

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.