OVH Cloud OVH Cloud

Demande precision sur code

10 réponses
Avatar
Christophe
Bonjour,

Je débute en Python et je viens de tomber sur mon premier truc
'bizarre'...

Pourquoi lorsque je fais :
toto = [0] * 100
toto est bien une liste de 100 éléments indépendants

et lorsque je fais :
titi = [[0,0,0]] * 100
titi n'est pas une liste de 100 triplets indépendants ?

Je n'ai du coup pas trouvé mieux que la solution suivante :
titi = [0] * 100
for i in range(100):
titi[i] = [0,0,0]

Quelle est ma faute de raisonnement ?
Est-ce qu'il y a une solution plus élégante ?

Merci !

10 réponses

Avatar
christophe dutrieux
Le Tue, 10 Aug 2004 01:18:35 +0200, Christophe a écrit :

Bonjour,

Je débute en Python et je viens de tomber sur mon premier truc
'bizarre'...

Pourquoi lorsque je fais :
toto = [0] * 100
toto est bien une liste de 100 éléments indépendants

et lorsque je fais :
titi = [[0,0,0]] * 100
titi n'est pas une liste de 100 triplets indépendants ?

Je n'ai du coup pas trouvé mieux que la solution suivante : titi = [0]
* 100
for i in range(100):
titi[i] = [0,0,0]

Quelle est ma faute de raisonnement ? Est-ce qu'il y a une solution plus
élégante ?

Merci !


Bizarre en effet car chez moi voici ce que ça donne:

IDLE 1.0.2
liste = [0]
print liste*10
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]



liste = [[0],[1]]
print liste*10
[[0], [1], [0], [1], [0], [1], [0], [1], [0], [1], [0], [1], [0], [1],



[0], [1], [0], [1], [0], [1]]
liste = [[2]]
print liste*10
[[2], [2], [2], [2], [2], [2], [2], [2], [2], [2]]



liste = [[0,1],[1,2]]
print liste*10
[[0, 1], [1, 2], [0, 1], [1, 2], [0, 1], [1, 2], [0, 1], [1, 2], [0, 1],



[1, 2], [0, 1], [1, 2], [0, 1], [1, 2], [0, 1], [1, 2], [0, 1], [1, 2],
[0, 1], [1, 2]]







Avatar
Damien Wyart
* Christophe in fr.comp.lang.python:
et lorsque je fais :
titi = [[0,0,0]] * 100
titi n'est pas une liste de 100 triplets indépendants ?


Chez moi, si :

Python 2.3.4 (#2, Aug 5 2004, 09:33:45)
[GCC 3.3.4 (Debian 1:3.3.4-7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
[[0,0,0]]*100
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0,



0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0,
0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0,
0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0,
0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0,
0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0,
0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0,
0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0],
[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0,
0], [0, 0, 0], [0, 0, 0]]

Est-ce qu'il y a une solution plus élégante ?


Avec une énumération de liste c'est assez lisible :

[[0,0,0] for _ in range(100)]

--
DW



Avatar
Sylvain Thenault
On Tue, 10 Aug 2004 01:18:35 +0200, Christophe wrote:

Bonjour,

Je débute en Python et je viens de tomber sur mon premier truc
'bizarre'...

Pourquoi lorsque je fais :
toto = [0] * 100
toto est bien une liste de 100 éléments indépendants

et lorsque je fais :
titi = [[0,0,0]] * 100
titi n'est pas une liste de 100 triplets indépendants ?

Je n'ai du coup pas trouvé mieux que la solution suivante : titi = [0] *
100
for i in range(100):
titi[i] = [0,0,0]

Quelle est ma faute de raisonnement ? Est-ce qu'il y a une solution plus
élégante ?


J'ai un doute sur ce que tu appelles "indépendant", mais je vais essayer
quand même de répondre...

En python, il faut garder à l'esprit que tout est référence (pointeur
pour ceux qui viennent du C). Quand tu fais :

titi = [[0,0,0]] * 100

tu crées une liste de 3 entiers, que tu répètes 100 fois. Tu te
retrouves donc avec une liste contenant 100 fois une référence vers la
même liste. Ce qui implique donc :

titi[0][0] = 1
titi
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0,



<snip>...]

Si tu veux avoir une liste contenant 100 listes de 3 entiers et non 100
références vers une même liste, tu peux utiliser une compréhension de
liste par exemple :

titi = [[0,0,0] for i in range(100)]

ici, la liste [0,0,0] est créée à chaque itération, donc tu obtiens
bien des références vers 100 listes différentes, et ce coup-ci :

titi[0][0] = 1
titi
[[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0,



<snip>...]

--
Sylvain Thénault LOGILAB, Paris (France).

http://www.logilab.com http://www.logilab.fr http://www.logilab.org



Avatar
Christophe
On Tue, 10 Aug 2004 11:01:54 +0200, Sylvain Thenault

Bonjour,

Je débute en Python et je viens de tomber sur mon premier truc
'bizarre'...

Pourquoi lorsque je fais :
toto = [0] * 100
toto est bien une liste de 100 éléments indépendants

et lorsque je fais :
titi = [[0,0,0]] * 100
titi n'est pas une liste de 100 triplets indépendants ?

Je n'ai du coup pas trouvé mieux que la solution suivante : titi > > [0] * 100
for i in range(100):
titi[i] = [0,0,0]

Quelle est ma faute de raisonnement ? Est-ce qu'il y a une solution
plus élégante ?


J'ai un doute sur ce que tu appelles "indépendant", mais je vais
essayer quand même de répondre...

En python, il faut garder à l'esprit que tout est référence (pointeur
pour ceux qui viennent du C). Quand tu fais :

titi = [[0,0,0]] * 100

tu crées une liste de 3 entiers, que tu répètes 100 fois. Tu te
retrouves donc avec une liste contenant 100 fois une référence vers la
même liste. Ce qui implique donc :

titi[0][0] = 1
titi
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1,



0,
<snip>...]

Si tu veux avoir une liste contenant 100 listes de 3 entiers et non
100 références vers une même liste, tu peux utiliser une compréhension
de liste par exemple :

titi = [[0,0,0] for i in range(100)]

ici, la liste [0,0,0] est créée à chaque itération, donc tu obtiens
bien des références vers 100 listes différentes, et ce coup-ci :

titi[0][0] = 1
titi
[[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0,



0,
<snip>...]



Ah d'accord.
Lorsque je tape [[0,0,0]] * N en fait c'est comme ci je faisais un
[tab] * N et c'est le même tableau tab qui est répété N fois ?
Parce qu'il est passé en référence ?

Par contre si tab est une valeur, dans ce cas il n'y a plus de notion de
passage par référence et on a bien des éléments indépendants ?

Subtile comme différence...

Du coup si je veux créer [0,0,0,0] et [[0],[0],[0],[0]] je ne peux pas
du tout utiliser la même syntaxe, alors que dans l'idée ces deux
tableaux ne sont pas si éloignés que ça...

Merci pour l'explication !




Avatar
Sylvain Thenault
On Wed, 11 Aug 2004 00:43:24 +0200, Christophe wrote:

On Tue, 10 Aug 2004 11:01:54 +0200, Sylvain Thenault

Bonjour,

Je débute en Python et je viens de tomber sur mon premier truc
'bizarre'...

Pourquoi lorsque je fais :
toto = [0] * 100
toto est bien une liste de 100 éléments indépendants

et lorsque je fais :
titi = [[0,0,0]] * 100
titi n'est pas une liste de 100 triplets indépendants ?

Je n'ai du coup pas trouvé mieux que la solution suivante : titi >> > [0] * 100
for i in range(100):
titi[i] = [0,0,0]

Quelle est ma faute de raisonnement ? Est-ce qu'il y a une solution
plus élégante ?


J'ai un doute sur ce que tu appelles "indépendant", mais je vais
essayer quand même de répondre...

En python, il faut garder à l'esprit que tout est référence (pointeur
pour ceux qui viennent du C). Quand tu fais :

titi = [[0,0,0]] * 100

tu crées une liste de 3 entiers, que tu répètes 100 fois. Tu te
retrouves donc avec une liste contenant 100 fois une référence vers la
même liste. Ce qui implique donc :

titi[0][0] = 1
titi
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1,



0,
<snip>...]

Si tu veux avoir une liste contenant 100 listes de 3 entiers et non
100 références vers une même liste, tu peux utiliser une compréhension
de liste par exemple :

titi = [[0,0,0] for i in range(100)]

ici, la liste [0,0,0] est créée à chaque itération, donc tu obtiens
bien des références vers 100 listes différentes, et ce coup-ci :

titi[0][0] = 1
titi
[[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0,



0,
<snip>...]



Ah d'accord.
Lorsque je tape [[0,0,0]] * N en fait c'est comme ci je faisais un
[tab] * N et c'est le même tableau tab qui est répété N fois ?
Parce qu'il est passé en référence ?


oui. Cela revient à faire :

tab = [0,0,0]
titi = [tab]*N

tab est une référence vers une liste de trois entier, de même que titi
est une référence vers une autre liste, de N élements (ici N
références vers la même liste de 3 entier). Pour résumer : en python,
on a pas de variables, uniquement des références vers des objets.

Par contre si tab est une valeur, dans ce cas il n'y a plus de notion de
passage par référence et on a bien des éléments indépendants ?


si, on a _toujours_ un passage par référence:

[id(i) for i in [0]*10]
[135523068, 135523068, 135523068, 135523068, 135523068, 135523068,



135523068, 135523068, 135523068, 135523068]

la différence c'est que en python, certains objet comme les nombres
(entiers, flottants) et les chaines de caractères sont immuables (non
modifiables).

--
Sylvain Thénault LOGILAB, Paris (France).

http://www.logilab.com http://www.logilab.fr http://www.logilab.org





Avatar
Christophe
On Wed, 11 Aug 2004 10:34:54 +0200, Sylvain Thenault

Ah d'accord.
Lorsque je tape [[0,0,0]] * N en fait c'est comme ci je faisais un
[tab] * N et c'est le même tableau tab qui est répété N fois ?
Parce qu'il est passé en référence ?


oui. Cela revient à faire :

tab = [0,0,0]
titi = [tab]*N

tab est une référence vers une liste de trois entier, de même que titi
est une référence vers une autre liste, de N élements (ici N
références vers la même liste de 3 entier). Pour résumer : en python,
on a pas de variables, uniquement des références vers des objets.

Par contre si tab est une valeur, dans ce cas il n'y a plus de
notion de passage par référence et on a bien des éléments
indépendants ?


si, on a _toujours_ un passage par référence:

[id(i) for i in [0]*10]
[135523068, 135523068, 135523068, 135523068, 135523068, 135523068,



135523068, 135523068, 135523068, 135523068]

la différence c'est que en python, certains objet comme les nombres
(entiers, flottants) et les chaines de caractères sont immuables (non
modifiables).




Alors là je suis encore plus embrouillé, si c'est le même objet à chaque
fois dans le tableau : [0] * 10
Pourquoi est-ce que je peux modifier chacun des éléments indépendamment
?




Avatar
Eric Brunel
Christophe wrote:
On Wed, 11 Aug 2004 10:34:54 +0200, Sylvain Thenault


Ah d'accord.
Lorsque je tape [[0,0,0]] * N en fait c'est comme ci je faisais un
[tab] * N et c'est le même tableau tab qui est répété N fois ?
Parce qu'il est passé en référence ?


oui. Cela revient à faire :

tab = [0,0,0]
titi = [tab]*N

tab est une référence vers une liste de trois entier, de même que titi
est une référence vers une autre liste, de N élements (ici N
références vers la même liste de 3 entier). Pour résumer : en python,
on a pas de variables, uniquement des références vers des objets.


Par contre si tab est une valeur, dans ce cas il n'y a plus de
notion de passage par référence et on a bien des éléments
indépendants ?


si, on a _toujours_ un passage par référence:


[id(i) for i in [0]*10]


[135523068, 135523068, 135523068, 135523068, 135523068, 135523068,


135523068, 135523068, 135523068, 135523068]

la différence c'est que en python, certains objet comme les nombres
(entiers, flottants) et les chaines de caractères sont immuables (non
modifiables).





Alors là je suis encore plus embrouillé, si c'est le même objet à chaque
fois dans le tableau : [0] * 10
Pourquoi est-ce que je peux modifier chacun des éléments indépendamment
?


Parce que tu ne modifies pas les *éléments*; tu modifies la *liste*. Compare:
l1 = [[0]] * 3
l2 = [0] * 3
l1
[[0], [0], [0]]



l2
[0, 0, 0]



l1[0][0] = 1
l1
[[1], [1], [1]]



l1[0] = [2]
l1
[[2], [1], [1]]



l2[0] = 3
l2
[3, 0, 0]




Dans le premier cas (l1[0][0] = 1), tu modifies non pas la liste l1, mais le
premier élément de la liste l1. Vu que ce *meme* élément est répété 3 fois dans
la liste, les seconds et troisième éléments de l1 sont le meme que le premier et
la modification est vue partout.

Dans le second cas (l1[0] = [2]), tu modifies la liste l1 elle-meme en remplçant
son premier élément. Dans ce cas, l'élément qui était déjà en première position
dans l1 n'est pas véritablement modifié, mais remplacé. Il n'y a donc pas
d'impact sur les second et troisième éléments de la liste.

Le troisième cas (l2[0] = 3) est en fait le meme que le second: tu ne modifies
pas la valeur de l'entier 0 en première position dans l2, mais tu remplaces le
premier élément de l2 par 3.

En fait, là où je comprendrais que tu sois complètement embrouillé, c'est avec
ce cas là:
l1 = [[0]] * 3
l2 = [0] * 3
l1
[[0], [0], [0]]



l2
[0, 0, 0]



l1[0] += [1]
l2[0] += 1
l1
[[0, 1], [0, 1], [0, 1]]



l2
[1, 0, 0]




Quand tu auras compris pourquoi ça fait ça, tu n'auras plus rien à apprendre sur
la façon de Python de gérer les variables.

Je te laisses réfléchir ;-)
--
- Eric Brunel <eric (underscore) brunel (at) despammed (dot) com> -
PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com





Avatar
Eric Brunel
Eric Brunel wrote:
[snip]
En fait, là où je comprendrais que tu sois complètement embrouillé,
c'est avec ce cas là:
l1 = [[0]] * 3
l2 = [0] * 3
l1
[[0], [0], [0]]



l2
[0, 0, 0]



l1[0] += [1]
l2[0] += 1
l1
[[0, 1], [0, 1], [0, 1]]



l2
[1, 0, 0]




Quand tu auras compris pourquoi ça fait ça, tu n'auras plus rien à
apprendre sur la façon de Python de gérer les variables.

Je te laisses réfléchir ;-)


Juste histoire de rajouter un autre cas bien pourri:

t = ([0],) * 3
t
([0], [0], [0])



t[0] += [1]
Traceback (most recent call last):



File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment
t
([0, 1], [0, 1], [0, 1])




Un petit indice: tout ça a à voir avec le caractères "mutable" / "immutable" des
objets Python et avec la façon de fonctionner de l'opérateur + --
- Eric Brunel <eric (underscore) brunel (at) despammed (dot) com> -
PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com




Avatar
Christophe
On Thu, 12 Aug 2004 09:45:35 +0200, Eric Brunel

En fait, là où je comprendrais que tu sois complètement embrouillé,
c'est avec ce cas là:
l1 = [[0]] * 3
l2 = [0] * 3
l1
[[0], [0], [0]]



l2
[0, 0, 0]



l1[0] += [1]
l2[0] += 1
l1
[[0, 1], [0, 1], [0, 1]]



l2
[1, 0, 0]




Quand tu auras compris pourquoi ça fait ça, tu n'auras plus rien à
apprendre sur la façon de Python de gérer les variables.

Je te laisses réfléchir ;-)


Bon ok après de longs jours de réflexion je pense avoir compris, ouf !
;-)

Lorsque je fais un l1 = [a] * N, l1 est en fait le même objet répété N
fois.
Lorsque a est un tableau (donc un pointeur), lorsque je modifie les
valeurs sur lequel pointent a, cela n'a pas d'importance pour l1 car on
ne modifie pas le pointeur a.
Par contre si je touche directement aux éléments de l1 et pas aux
éléments de a, là ça change bien l1 directement.

En tout cas j'ai compris que dans l1 = [0] * N, c'est bien le même 0 qui
est répété N fois !

Merci !




Avatar
Christophe
On Thu, 12 Aug 2004 09:50:44 +0200, Eric Brunel

Eric Brunel wrote:
[snip]
En fait, là où je comprendrais que tu sois complètement embrouillé,
c'est avec ce cas là:
l1 = [[0]] * 3
l2 = [0] * 3
l1
[[0], [0], [0]]



l2
[0, 0, 0]



l1[0] += [1]
l2[0] += 1
l1
[[0, 1], [0, 1], [0, 1]]



l2
[1, 0, 0]




Quand tu auras compris pourquoi ça fait ça, tu n'auras plus rien à
apprendre sur la façon de Python de gérer les variables.

Je te laisses réfléchir ;-)


Juste histoire de rajouter un autre cas bien pourri:

t = ([0],) * 3
t
([0], [0], [0])



t[0] += [1]
Traceback (most recent call last):



File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment
t
([0, 1], [0, 1], [0, 1])




Un petit indice: tout ça a à voir avec le caractères "mutable" /
"immutable" des objets Python et avec la façon de fonctionner de
l'opérateur +
Là par contre je ne comprends plus...

Quelle est la meilleur documentation actuellement disponible en français
sur Python ? j'ai encore pas mal de choses à apprendre je crois...