cerhu > comp.lang.* > comp.lang.python

Christophe (10/08/2004, 01h18)
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 !
christophe dutrieux (10/08/2004, 06h31)
Le Tue, 10 Aug 2004 01:18:35 +0200, Christophe a écrit :

[..]
> 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]]
Damien Wyart (10/08/2004, 08h22)
* Christophe <chris_invalid> 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)]
Sylvain Thenault (10/08/2004, 11h01)
On Tue, 10 Aug 2004 01:18:35 +0200, Christophe wrote:

[..]
> 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>...]
Christophe (11/08/2004, 00h43)
On Tue, 10 Aug 2004 11:01:54 +0200, Sylvain Thenault
<sylvain.thenault> wrote :

[..]
> 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 :
> [[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 !
Sylvain Thenault (11/08/2004, 10h34)
On Wed, 11 Aug 2004 00:43:24 +0200, Christophe wrote:

> On Tue, 10 Aug 2004 11:01:54 +0200, Sylvain Thenault
> <sylvain.thenault> wrote :
>> 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).
Christophe (12/08/2004, 01h29)
On Wed, 11 Aug 2004 10:34:54 +0200, Sylvain Thenault
<sylvain.thenault> wrote :

[..]
> si, on a _toujours_ un passage par référence:
> [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
?
Eric Brunel (12/08/2004, 09h45)
Christophe wrote:
> On Wed, 11 Aug 2004 10:34:54 +0200, Sylvain Thenault
> <sylvain.thenault> wrote :
>> 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:

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à:

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 (12/08/2004, 09h50)
Eric Brunel wrote:
[snip]
> En fait, là où je comprendrais que tu sois complètement embrouillé,
> c'est avec ce cas là:
> [[0], [0], [0]]
> [0, 0, 0]
> [[0, 1], [0, 1], [0, 1]]
> [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 +=
Christophe (16/08/2004, 01h52)
On Thu, 12 Aug 2004 09:45:35 +0200, Eric Brunel
<eric_brunel> wrote :

> En fait, là où je comprendrais que tu sois complètement embrouillé,
> c'est avec ce cas là:
> [[0], [0], [0]]
> [0, 0, 0]
> [[0, 1], [0, 1], [0, 1]]
> [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 !
Christophe (16/08/2004, 01h52)
On Thu, 12 Aug 2004 09:50:44 +0200, Eric Brunel
<eric_brunel> wrote :

> Eric Brunel wrote:
> [snip]
> Juste histoire de rajouter un autre cas bien pourri:
> ([0], [0], [0])
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> TypeError: object doesn't support item assignment
> ([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...
Discussions similaires
demande de precision

re . re ; demande de precision sur le statut de vdi

demande de précision

demande de precision


Fuseau horaire GMT +2. Il est actuellement 01h33. | Privacy Policy