Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Petites questions théoriques : peut-on comparer une variable liste avec un pointeur en C?

0 views
Skip to first unread message

Francois

unread,
Apr 8, 2008, 3:34:15 PM4/8/08
to
Bonjour à tous,

J'ai quelques questions qui peut-être auront un rapport avec
l'implémentation, mais cela m'intéresse quand même.


1) Quand on fait

a = 2
b = a

Les deux variables a et b sont deux variables différentes, la zone
mémoire allouée pour a et celle pour b sont distinctes. Une modification
de a n'affectera pas b etc. Chacun vit ça vie.

Ce qui me chagrine, c'est que id(a) et id(b) me donne exactement la même
valeur, alors que, pour moi, a et b sont distinctes. D'ailleurs quand je
modifie b (via b = 50 par exemple), là, ce petit coquin de Python ne me
donne plus le même id (et heureusement). Avez vous une explication ?


2) Pour les listes, c'est différent et c'est bien dit dans les docs. Par
exemple :

l1 = [0,1,2,3,4]
l2 = l1

J'ai bien compris que "le nom l2 est un alias du nom l1" qui désigne le
même objet dans la mémoire de l'ordinateur. Une modification via l1 se
retrouvera en appelant la liste via l2. Par exemple :

l1[0] = 100

entraînera l2 de la forme [100,1,2,3,4]

Je voulais trouver une petite explication à cela. J'aimerais avoir votre
avis. Je me suis dit que, peut-être, l1 et l2 étaient des sortes de
pointeurs (comme en C) sur le premier élément de la liste.


3) J'ai lu ceci "avec a = 3, a est une référence, c'est-à-dire un nom
désignant l'emplacement mémoire d'une valeur (objet)". Cela veut-il dire
qu'en fait les variables dans Python sont toutes "des pointeurs en C" ?

--
François

bruno.des...@gmail.com

unread,
Apr 8, 2008, 5:04:36 PM4/8/08
to
On 8 avr, 21:34, Francois <mathsatta...@free.fr> wrote:
> Bonjour à tous,
>
> J'ai quelques questions qui peut-être auront un rapport avec
> l'implémentation, mais cela m'intéresse quand même.
>
> 1) Quand on fait
>
> a = 2
> b = a
>
> Les deux variables a et b sont deux variables différentes,

a et b sont deux noms différents. A ce stade, ils sont associés à une
référence sur le même objet.

> la zone
> mémoire allouée pour a et celle pour b sont distinctes.

Si tu commences à raisonner avec les concepts du C, tu vas te faire du
mal pour rien. En Python, une variable n'est pas une étiquette sur une
adresse mémoire, c'est un nom associé à une référence sur un objet. Le
nom lui-même n'est rien d'autre que ça : un nom. Une clé dans une
table de hachage, si tu préfère (et accessoirement, hormis pour les
variables locales d'une fonction, c'est exactement ça : une clé dans
une table de hachage). Quant à la zone mémoire où réside l'objet (les
zones mémoires, d'ailleurs, vu que c'est un type de donnée structuré
composé en partie de références sur d'autres objets...), c'est
l'affaire de la machine virtuelle. De ton point de vue, il pourrait
aussi bien être sur une tablette d'argile.

Donc,en bref, oublie les zones mémoires, et pense en termes d'objets.
Et dans ton cas, non, a et b référencent le *même* objet. En Python,
une assignation signifie "associe ce nom avec une référence sur cet
objet (ie : a = 2) ou sur l'objet référéncé par ce nom (ie: b = a)".
Un objet n'est *jamais* copié si tu ne le demande pas très
explicitement (en utilisant copy.copy() ou copy.deepcopy()).

> Une modification
> de a

Pour quelle définition de "modification" ? changement de l'état de
l'objet référencé par a, ou rebinding (réassignation) d'un autre objet
sur a ?

Dans le premier cas, vu que 2 est un objet immutable, tu ne peux tout
simplement pas le modifier. Avec un objet mutable, par contre, toute
modification de l'objet sera 'visible' depuis tous les noms
référençant cet objet (et pour cause...). Par exemple:

c = [1]
d = c
c[0] = 2
print d
d.append(42)
print c

Dans le second cas (réassignation), faire pointer un nom sur un autre
objet est bien sûr sans incidence sur les autres paires nom:référence
pointant sur l'objet d'origine, ie:

c = [1]
d = c
assert id(c) == id(d)
# equivalent:
assert c is d

c = 'toto'
assert d is not c


> n'affectera pas b etc. Chacun vit ça vie.

cf ci-dessus.

> Ce qui me chagrine, c'est que id(a) et id(b) me donne exactement la même
> valeur,

C'est normal.

> alors que, pour moi, a et b sont distinctes.

les noms sont distinct. Mais ils pointent sur le même objet. C'est
équivalent à:

ns = {}
ns['a'] = 2
ns['b'] = ns['a']

Là, tu t'attends bien à ce que ns['a'] et ns['b']
"soient" (référencent) le même objet. Après, si tu fais:

ns['b'] = 50

tu t'attends aussi à ce que ns['b'] pointe sur un objet différent.

Si ton code est au top-level de ton script ou module (ou de
l'interpréteur), tu peux s/ns/globals()/g

> D'ailleurs quand je
> modifie b (via b = 50 par exemple)

Tu ne modifie pas 'b', tu le fait pointer sur un autre objet. Ce qui
est sans conséquence sur l'objet précédemment référencé par b (si ce
n'est de décrémemter son compteur de références).

>, là, ce petit coquin de Python ne me
> donne plus le même id (et heureusement). Avez vous une explication ?

cf ci-dessus.

> 2) Pour les listes, c'est différent

Absolument pas. Ni pour aucune autre sorte d'objet.

> et c'est bien dit dans les docs. Par
> exemple :
>
> l1 = [0,1,2,3,4]
> l2 = l1
>
> J'ai bien compris que "le nom l2 est un alias du nom l1" qui désigne le
> même objet dans la mémoire de l'ordinateur. Une modification via l1 se
> retrouvera en appelant la liste via l2. Par exemple :
>
> l1[0] = 100
>
> entraînera l2 de la forme [100,1,2,3,4]

Il y a une nette différence entre :
l1[0] = 100
et
1l = 100

Le premier est en fait du sucre syntaxique pour
l1.__setitem__(0, 100)

Bref, un appel de méthode qui va modifier l'état de la liste
référencée par l1.

> Je voulais trouver une petite explication à cela. J'aimerais avoir votre
> avis. Je me suis dit que, peut-être, l1 et l2 étaient des sortes de
> pointeurs

une référence

> (comme en C)

en l'occurence, comme en C++ ou en Java

> sur le premier élément de la liste.

sur l'objet liste.


En Python, tu n'a *que* des références sur des objets, *jamais* de
types 'immédiat' comme en C. Ne laisse pas la syntaxe te tromper, ce
n'est pas parce que tu définis un objet via une expression littérale
que tu a autre chose qu'une référence sur un objet.

> 3) J'ai lu ceci "avec a = 3, a est une référence, c'est-à-dire un nom
> désignant l'emplacement mémoire d'une valeur (objet)".

Bien qu'à peu près correcte (au moins pour CPython), cette explication
n'est AMHA pas très bonne en ce qu'elle fait appel à une notion
(l'emplacement mémoire) qui n'existes tout simplement pas dans le
langage (même si elle existe, bien sûr, dans l'implémentation du
langage...).

> Cela veut-il dire
> qu'en fait les variables dans Python sont toutes "des pointeurs en C" ?

Non, même pas. Une variable C de type pointeur contient une adresse
mémoire. Un nom ne contient rien - une clé dans une table de hachage
ne contient rien.

Francois

unread,
Apr 8, 2008, 7:12:40 PM4/8/08
to
Déjà, grand merci pour toutes tes explications.

bruno.des...@gmail.com a écrit :


> Si tu commences à raisonner avec les concepts du C, tu vas te faire du
> mal pour rien. En Python, une variable n'est pas une étiquette sur une
> adresse mémoire, c'est un nom associé à une référence sur un objet. Le
> nom lui-même n'est rien d'autre que ça : un nom. Une clé dans une
> table de hachage, si tu préfère (et accessoirement, hormis pour les
> variables locales d'une fonction, c'est exactement ça : une clé dans
> une table de hachage).

Ah oui, tiens, et les variables locales d'une fonctions ? C'est aussi un
nom associé à une référence sauf que l'espace des noms dans lequel elle
se trouve est dans un espace temporaire disjoint de l'espace de nom du
script principal ?

> Quant à la zone mémoire où réside l'objet (les
> zones mémoires, d'ailleurs, vu que c'est un type de donnée structuré
> composé en partie de références sur d'autres objets...), c'est
> l'affaire de la machine virtuelle. De ton point de vue, il pourrait
> aussi bien être sur une tablette d'argile.

Je comprends cette logique : il faut rester dans le cadre du langage
abstrait et ne pas rentrer dans l'implémentation. Tu as raison. Mais,
dès fois, je trouve que rentrer (un tout petit peu) dans
l'implémentation, ça m'aide à comprendre.


> Donc,en bref, oublie les zones mémoires, et pense en termes d'objets.
> Et dans ton cas, non, a et b référencent le *même* objet. En Python,
> une assignation signifie "associe ce nom avec une référence sur cet
> objet (ie : a = 2) ou sur l'objet référéncé par ce nom (ie: b = a)".
> Un objet n'est *jamais* copié si tu ne le demande pas très
> explicitement (en utilisant copy.copy() ou copy.deepcopy()).

Là, je crois que *tout* est dit dans ce paragraphe très clair. Je résume
pour voir.

1) En *C*, une variable est un objet (un peu au sens de Python, avec un
type [taille + façon d'être interprété], une adresse et une valeur). On
peut donc parler de l'adresse d'une variable. Deux variables avec des
noms différents ont chacune une adresse différente.

2) Avec *Python*, une variable est un simple nom faisant référence à un
objet (avec un type [taille + façon d'être interprété], une adresse et
une valeur). Une variable n'a pas d'adresse. Deux variables avec des
noms différents peuvent très bien référencer un même objet.

Par exemple avec ceci (en Python)

a=1
b=1
c=1

finalement, dans la mémoire se trouve un seul objet créé (l'entier 1).
Alors qu'avec l'équivalent en C, trois objets seraient crées (de même
valeur, mais à trois endroits différents).

Si j'ai bon, je crois que j'ai franchi un petit cap dans ma
compréhension de Python. :-)

Remarque en passant : Je me doutais bien que d'un langage à un autre,
des mêmes notions pouvaient avoir une implémentation différente. Mais
quand même, je n'imaginais pas que cela serait le cas pour la basique
notion de variable par exemple ! J'espère que d'un langage à un autre,
il ne faut pas tout réapprendre à chaque fois (car là, finalement, j'ai
du réapprendre ce qu'est une variable :-) ) ?


> Tu ne modifie pas 'b', tu le fait pointer sur un autre objet. Ce qui
> est sans conséquence sur l'objet précédemment référencé par b (si ce
> n'est de décrémemter son compteur de références).

D'accord. Dans mes autres messages, j'ai du écrire cette erreur 20 fois.
Je crois que c'est compris. Ce qui m'intéresse ici, c'est la notion de
compteur de référence. Chaque objet possède un compteur de référence,
c'est-à-dire, si je comprends bien, un compteur qui donne le nombre de
variable qui font référence à cet objet. C'est ça ?

Heu ..., mais ça sert à quoi ? À effacer l'objet de la mémoire quand le
compteur est à 0 peut-être ?


> Il y a une nette différence entre :
> l1[0] = 100
> et

> l1 = 100


>
> Le premier est en fait du sucre syntaxique pour
> l1.__setitem__(0, 100)
>
> Bref, un appel de méthode qui va modifier l'état de la liste
> référencée par l1.

Ok, on garde une certaine cohérence sur le tout objet : avec [], on
applique sans le savoir une méthode à l'objet l1. Tu ne l'as pas précisé
mais avec l1 = 100, évidemment, on réassigne l1 vers un nouvel objet qui
n'est plus une liste.

>> Je voulais trouver une petite explication à cela. J'aimerais avoir votre
>> avis. Je me suis dit que, peut-être, l1 et l2 étaient des sortes de
>> pointeurs
>
> une référence
>
>> (comme en C)
>
> en l'occurence, comme en C++ ou en Java
>
>> sur le premier élément de la liste.
>
> sur l'objet liste.

Ok, ok. Allez, quand même, en interne de chez interne (dans le code C de
CPython par exemple), il n'y a pas de pointeur qui traîne quelque part
dans la définition d'une variable Python ? Hein, pour me faire plaisir. :-)


> En Python, tu n'a *que* des références sur des objets, *jamais* de
> types 'immédiat' comme en C. Ne laisse pas la syntaxe te tromper, ce
> n'est pas parce que tu définis un objet via une expression littérale
> que tu a autre chose qu'une référence sur un objet.

Heu, un type immédiat c'est quoi ?


>> Cela veut-il dire
>> qu'en fait les variables dans Python sont toutes "des pointeurs en C" ?
>
> Non, même pas. Une variable C de type pointeur contient une adresse
> mémoire. Un nom ne contient rien - une clé dans une table de hachage
> ne contient rien.

Allez, il n'y a pas un petit pointeur caché quelque part ...


--
François

Francois

unread,
Apr 8, 2008, 8:29:56 PM4/8/08
to
Francois a écrit :
> bruno.des...@gmail.com a écrit :

>> Il y a une nette différence entre :
>> l1[0] = 100
>> et
>> l1 = 100
>>
>> Le premier est en fait du sucre syntaxique pour
>> l1.__setitem__(0, 100)
>>
>> Bref, un appel de méthode qui va modifier l'état de la liste
>> référencée par l1.
>
> Ok, on garde une certaine cohérence sur le tout objet : avec [], on
> applique sans le savoir une méthode à l'objet l1. Tu ne l'as pas précisé
> mais avec l1 = 100, évidemment, on réassigne l1 vers un nouvel objet qui
> n'est plus une liste.

Plus j'y pense, plus je me dis que la syntaxe l1[0]=100 est vraiment
traître. Elle fait vraiment penser à une réassignation comme l1 = 100,
alors qu'en fait c'est une méthode appliquée à un objet ("mutable") pour
le modifier (évidemment la syntaxe l1[0]=100 est quand même
incontournable du point de vue pratique). C'est ça qui m'a induit en
erreur :

a = 2
b = a # a et b font référence au même objet
b = 5 # c'est une assignation de b vers un nouvel objet
# ce n'est pas une modification de l'objet référencé
# par b qui est non mutable
print a # donne 2
print b # donne 5 car b ne se réfère plus au même objet que a


a = [0,1,2,3]
b = a # a et b font référence au même objet
b[0] = 7 # ce n'est pas une assignation
# c'est une modification de l'objet (mutable)
# référencé par b, via une méthode
print a # donne [7,1,2,3] l'objet référencé par a et b est le
# même et il a subi une modification en cours de route
print b # donne [7,1,2,3]


Une réassignation ne modifie pas un objet, mais créé une référence vers
un nouvel objet. On peut modifier un objet, à condition qu'il soit
mutable, mais cela ne peut pas passer par une réassignation. Par une
méthode par exemple. Et b[0]=7, n'est pas une réassignation mais une
méthode cachée (la bougresse).

--
François

Francois

unread,
Apr 8, 2008, 8:53:17 PM4/8/08
to
Francois a écrit :

> b[0] = 7 # ce n'est pas une assignation

Bon, là j'exagère un peu. b[0]=7 est (je pense) une assignation du
premier élément de l'objet séquence référencé par a (ou par b), mais ce
n'est pas une modification de l'objet 0 (ancien objet référencé par
b[0]) mais plutôt une création d'une référence de b[0] vers le nouvel
objet 7. Cette réassignation, de fait, entraîne une modification de
l'objet séquence référencé par b et aussi par a.


--
François qui commence à ce mélanger les pinceaux et qui ferait mieux
d'aller se coucher. :-)

bruno.des...@gmail.com

unread,
Apr 8, 2008, 9:08:03 PM4/8/08
to
On 9 avr, 01:12, Francois <mathsatta...@free.fr> wrote:
> Déjà, grand merci pour toutes tes explications.
>
> bruno.desthuilli...@gmail.com a écrit :

>
> > Si tu commences à raisonner avec les concepts du C, tu vas te faire du
> > mal pour rien. En Python, une variable n'est pas une étiquette sur une
> > adresse mémoire, c'est un nom associé à une référence sur un objet. Le
> > nom lui-même n'est rien d'autre que ça : un nom. Une clé dans une
> > table de hachage, si tu préfère (et accessoirement, hormis pour les
> > variables locales d'une fonction, c'est exactement ça : une clé dans
> > une table de hachage).
>
> Ah oui, tiens, et les variables locales d'une fonctions ? C'est aussi un
> nom associé à une référence sauf que l'espace des noms dans lequel elle
> se trouve est dans un espace temporaire disjoint de l'espace de nom du
> script principal ?

Exactement. Note bien que ce sont les *noms* qui sont locaux, pas les
objets qu'ils référencent. C'est particulièrement important à
comprendre pour les paramètres de fonction: si tu modifie (mutation)
un objet passé en paramètre, bien que le nom par lequel tu accèdes à
l'objet soit local, l'objet, lui, est bien celui qui a été passé à la
fonction. Par contre, si tu rebinde un paramètre, ça n'affecte que
l'espace de nommage local. Exemple:


def unefonc(liste, dico):
liste.append(42)
dico = 'allo'

uneliste = [1, 2, 3]
undico = dict(a=1, b=2, c=3)

print uneliste, undico
unefonc(uneliste, undico)
print uneliste, undico

> > Quant à la zone mémoire où réside l'objet (les
> > zones mémoires, d'ailleurs, vu que c'est un type de donnée structuré
> > composé en partie de références sur d'autres objets...), c'est
> > l'affaire de la machine virtuelle. De ton point de vue, il pourrait
> > aussi bien être sur une tablette d'argile.
>
> Je comprends cette logique : il faut rester dans le cadre du langage
> abstrait et ne pas rentrer dans l'implémentation. Tu as raison. Mais,
> dès fois, je trouve que rentrer (un tout petit peu) dans
> l'implémentation, ça m'aide à comprendre.

Tout à fait d'accord. "dès fois", et "un petit peu". En sachant que
d'autres implémentations sont possibles - au moins théoriquement, mais
parfois aussi pratiquement. Le problème pour toi, ici, c'est de
commencer par faire abstraction (justement) de ce que tu a appris pour
le C.

> > Donc,en bref, oublie les zones mémoires, et pense en termes d'objets.
> > Et dans ton cas, non, a et b référencent le *même* objet. En Python,
> > une assignation signifie "associe ce nom avec une référence sur cet
> > objet (ie : a = 2) ou sur l'objet référéncé par ce nom (ie: b = a)".
> > Un objet n'est *jamais* copié si tu ne le demande pas très
> > explicitement (en utilisant copy.copy() ou copy.deepcopy()).
>
> Là, je crois que *tout* est dit dans ce paragraphe très clair. Je résume
> pour voir.
>
> 1) En *C*, une variable est un objet (un peu au sens de Python, avec un
> type [taille + façon d'être interprété], une adresse et une valeur). On
> peut donc parler de l'adresse d'une variable. Deux variables avec des
> noms différents ont chacune une adresse différente.

admettons. minus le "un peu au sens de Python".

> 2) Avec *Python*, une variable est un simple nom faisant référence à un
> objet (avec un type [taille + façon d'être interprété],

La notion de type est totalement différente.

Selon les catégories du C, il n'existe qu'un seul type en Python, le
type Py_Object_ptr, qui est un pointeur sur une structure de données
(je parle bien sûr de l'implémentation CPython - en Jython ou
IronPython, c'est probablement différent) (et bien sûr, je simplifie
outrageusement).

Selon la sémantique propre à Python, le 'type' d'un objet, c'est
l'objet class (int, dict, function, etc) qu'il référence via son
attribut __class__. A ce niveau, il n'y a pas de notion de 'taille',
de 'façon d'être interprété' ou autre. Il y a juste une référence sur
un autre objet dans lequel l'interpréteur ira chercher les attributs
non trouvés dans l'objet lui-même.

> une adresse et
> une valeur). Une variable n'a pas d'adresse. Deux variables avec des
> noms différents peuvent très bien référencer un même objet.

Oui.

> Par exemple avec ceci (en Python)
>
> a=1
> b=1
> c=1
>
> finalement, dans la mémoire se trouve un seul objet créé (l'entier 1).

Avec CPython, oui, mais parce que les petits entiers sont conservé en
cache. Si tu remplace 1 par 33333, tu aura trois objets différents.
Par contre, si tu fais:

a = 33333
b = a
c = b

Tu aura bien trois noms référençant un seul et même objet.


> Alors qu'avec l'équivalent en C, trois objets seraient crées (de même
> valeur, mais à trois endroits différents).

Oui.

> Si j'ai bon, je crois que j'ai franchi un petit cap dans ma
> compréhension de Python. :-)

Y a du progrès.

> Remarque en passant : Je me doutais bien que d'un langage à un autre,
> des mêmes notions pouvaient avoir une implémentation différente. Mais
> quand même, je n'imaginais pas que cela serait le cas pour la basique
> notion de variable par exemple !

Attends de voir un langage fonctionnel pur (comme Haskell par
exemple) : tu ne peux tout simplement pas modifier la valeur d'une
variable une fois qu'elle est crée !-)

> J'espère que d'un langage à un autre,
> il ne faut pas tout réapprendre à chaque fois (car là, finalement, j'ai
> du réapprendre ce qu'est une variable :-) ) ?

Non, la sémantique des variables de Python (de ce point de vue là) se
retrouve, à l'identique ou de façon très proche, dans pas mal d'autres
langages de haut niveau. De même que la sémantique des variables C se
retrouve dans pas mal de langages de bas niveau.

> > Tu ne modifie pas 'b', tu le fait pointer sur un autre objet. Ce qui
> > est sans conséquence sur l'objet précédemment référencé par b (si ce
> > n'est de décrémemter son compteur de références).
>
> D'accord. Dans mes autres messages, j'ai du écrire cette erreur 20 fois.
> Je crois que c'est compris. Ce qui m'intéresse ici, c'est la notion de
> compteur de référence. Chaque objet possède un compteur de référence,
> c'est-à-dire, si je comprends bien, un compteur qui donne le nombre de
> variable qui font référence à cet objet. C'est ça ?

pile-poil.

> Heu ..., mais ça sert à quoi ? À effacer l'objet de la mémoire quand le
> compteur est à 0 peut-être ?

bingo !-)

> > Il y a une nette différence entre :
> > l1[0] = 100
> > et
> > l1 = 100
>
> > Le premier est en fait du sucre syntaxique pour
> > l1.__setitem__(0, 100)
>
> > Bref, un appel de méthode qui va modifier l'état de la liste
> > référencée par l1.
>
> Ok, on garde une certaine cohérence sur le tout objet : avec [], on
> applique sans le savoir

moi, je le sais !-)

En pratique, à part l'assignation à un nom simple (ie: sans '.' ni []
dans l'affaire), toutes les opérations de Python sont en fait des
appels de méthode, et toutes sont surchargeables.

> une méthode à l'objet l1. Tu ne l'as pas précisé
> mais avec l1 = 100, évidemment, on réassigne l1 vers un nouvel objet qui
> n'est plus une liste.

Indeed.

> >> Je voulais trouver une petite explication à cela. J'aimerais avoir votre
> >> avis. Je me suis dit que, peut-être, l1 et l2 étaient des sortes de
> >> pointeurs
>
> > une référence
>
> >> (comme en C)
>
> > en l'occurence, comme en C++ ou en Java
>
> >> sur le premier élément de la liste.
>
> > sur l'objet liste.
>
> Ok, ok. Allez, quand même, en interne de chez interne (dans le code C de
> CPython par exemple), il n'y a pas de pointeur qui traîne quelque part
> dans la définition d'une variable Python ? Hein, pour me faire plaisir. :-)

Si, bien sûr. cf ci-dessus pour l'implémentation du type objet dans
CPython. A vrai dire, y a même tellement de pointeurs que tu ne sais
plus où donner de la tête. Content ?-)

> > En Python, tu n'a *que* des références sur des objets, *jamais* de
> > types 'immédiat' comme en C. Ne laisse pas la syntaxe te tromper, ce
> > n'est pas parce que tu définis un objet via une expression littérale
> > que tu a autre chose qu'une référence sur un objet.
>
> Heu, un type immédiat c'est quoi ?

un entier en C.

> >> Cela veut-il dire
> >> qu'en fait les variables dans Python sont toutes "des pointeurs en C" ?
>
> > Non, même pas. Une variable C de type pointeur contient une adresse
> > mémoire. Un nom ne contient rien - une clé dans une table de hachage
> > ne contient rien.
>
> Allez, il n'y a pas un petit pointeur caché quelque part ...

Tu y tiens, hein ?-)

Mais bon, il y a d'autres implémentations de Python, dans des langages
qui ne supportent pas les pointeurs (Jython et IronPython). Ce qui
démontre bien que la notion de pointeur n'est pas nécessaire ni pour
implémenter Python, ni pour le comprendre. (NB : bon, ok, Java (et
probablement .NET) est aussi implémenté en C, donc on finis *toujours*
par avoir des bits à des adresses mémoires...)

Amaury Forgeot d'Arc

unread,
Apr 8, 2008, 9:08:24 PM4/8/08
to
Francois a écrit :

> Francois a écrit :
>> b[0] = 7 # ce n'est pas une assignation
>
> Bon, là j'exagère un peu. b[0]=7 est (je pense) une assignation du
> premier élément de l'objet séquence référencé par a (ou par b), mais ce
> n'est pas une modification de l'objet 0 (ancien objet référencé par
> b[0]) mais plutôt une création d'une référence de b[0] vers le nouvel
> objet 7. Cette réassignation, de fait, entraîne une modification de
> l'objet séquence référencé par b et aussi par a.

Il y en a au moins un qui se couchera plus savant cette nuit.

--
Amaury

bruno.des...@gmail.com

unread,
Apr 8, 2008, 9:13:16 PM4/8/08
to
On 9 avr, 02:29, Francois <mathsatta...@free.fr> wrote:
(snip)

> Plus j'y pense, plus je me dis que la syntaxe l1[0]=100 est vraiment
> traître. Elle fait vraiment penser à une réassignation comme l1 = 100,
> alors qu'en fait c'est une méthode appliquée à un objet ("mutable") pour
> le modifier (évidemment la syntaxe l1[0]=100 est quand même
> incontournable du point de vue pratique). C'est ça qui m'a induit en
> erreur :

T'inquiètes pas, t'es pas le premier (et c'est pas non plus la
première fois que j'explique ça).

> a = 2
> b = a # a et b font référence au même objet
> b = 5 # c'est une assignation de b vers un nouvel objet
> # ce n'est pas une modification de l'objet référencé
> # par b qui est non mutable
> print a # donne 2
> print b # donne 5 car b ne se réfère plus au même objet que a
>
> a = [0,1,2,3]
> b = a # a et b font référence au même objet
> b[0] = 7 # ce n'est pas une assignation
> # c'est une modification de l'objet (mutable)
> # référencé par b, via une méthode
> print a # donne [7,1,2,3] l'objet référencé par a et b est le
> # même et il a subi une modification en cours de route
> print b # donne [7,1,2,3]
>
> Une réassignation ne modifie pas un objet, mais créé une référence vers
> un nouvel objet. On peut modifier un objet, à condition qu'il soit
> mutable, mais cela ne peut pas passer par une réassignation. Par une
> méthode par exemple.

Par une méthode uniquement. Même si l'appel de méthode n'est pas
explicite.

> Et b[0]=7, n'est pas une réassignation mais une
> méthode cachée (la bougresse).

Certes, mais elle est tellement plus élégante comme ça qu'on lui
pardonne !-)

Bon, je crois que t'es bon, là.

bruno.des...@gmail.com

unread,
Apr 8, 2008, 9:24:09 PM4/8/08
to
On 9 avr, 03:08, Amaury Forgeot d'Arc <afaNOS...@neuf.fr> wrote:
> Francois a écrit :
>
> > Francois a écrit :
> >> b[0] = 7 # ce n'est pas une assignation
>
> > Bon, là j'exagère un peu. b[0]=7 est (je pense) une assignation du
> > premier élément de l'objet séquence référencé par a (ou par b),

Dans la cas d'une liste, oui, on en arrive finalement à ça. Mais je
pourrais écrire une classe telle que la même syntaxe n'effectue aucune
assignation.

> > mais ce
> > n'est pas une modification de l'objet 0 (ancien objet référencé par
> > b[0]) mais plutôt une création d'une référence de b[0] vers le nouvel
> > objet 7.

Je ne sais pas pourquoi, mais cette formulation me semble ambigüe...

> > Cette réassignation, de fait, entraîne une modification de
> > l'objet séquence référencé par b et aussi par a.

Tout à fait. Mais ne modifie pas l'espace de nommage en cours, et
n'affecte pas les liaisons entre a et b et l'objet séquence (précision
à l'adresse de l'OP).


> Il y en a au moins un qui se couchera plus savant cette nuit.

A ce propos, je ne sais pas si je suis plus savant, mais il serait
temps que j'y aille...

Francois

unread,
Apr 8, 2008, 9:36:07 PM4/8/08
to
bruno.des...@gmail.com a écrit :

> On 9 avr, 02:29, Francois <mathsatta...@free.fr> wrote:
> (snip)
>> Plus j'y pense, plus je me dis que la syntaxe l1[0]=100 est vraiment
>> traître. Elle fait vraiment penser à une réassignation comme l1 = 100,
>> alors qu'en fait c'est une méthode appliquée à un objet ("mutable") pour
>> le modifier (évidemment la syntaxe l1[0]=100 est quand même
>> incontournable du point de vue pratique). C'est ça qui m'a induit en
>> erreur :
>
> T'inquiètes pas, t'es pas le premier (et c'est pas non plus la
> première fois que j'explique ça).

Ah, désolé. Faut dire, à ma décharge, que tout cela n'est pas vraiment
bien expliqué dans le peu de livres que j'ai.


>> Une réassignation ne modifie pas un objet, mais créé une référence vers
>> un nouvel objet. On peut modifier un objet, à condition qu'il soit
>> mutable, mais cela ne peut pas passer par une réassignation. Par une
>> méthode par exemple.
>
> Par une méthode uniquement. Même si l'appel de méthode n'est pas
> explicite.

Par une méthode *uniquement*, Ok. C'est précis et simple. Ça me va !


>> Et b[0]=7, n'est pas une réassignation mais une
>> méthode cachée (la bougresse).
>
> Certes, mais elle est tellement plus élégante comme ça qu'on lui
> pardonne !-)

Oui, demain matin tout cela sera pardonné. Oops, on est déjà demain
matin. :-)


> Bon, je crois que t'es bon, là.

Moins mal qu'il y a quelques heures en tout cas. Merci encore.


--
François

Francois

unread,
Apr 8, 2008, 10:10:11 PM4/8/08
to
bruno.des...@gmail.com a écrit :

> On 9 avr, 01:12, Francois <mathsatta...@free.fr> wrote:
>> Ah oui, tiens, et les variables locales d'une fonctions ? C'est aussi un
>> nom associé à une référence sauf que l'espace des noms dans lequel elle
>> se trouve est dans un espace temporaire disjoint de l'espace de nom du
>> script principal ?
>
> Exactement. Note bien que ce sont les *noms* qui sont locaux, pas les
> objets qu'ils référencent. C'est particulièrement important à
> comprendre pour les paramètres de fonction: si tu modifie (mutation)
> un objet passé en paramètre, bien que le nom par lequel tu accèdes à
> l'objet soit local, l'objet, lui, est bien celui qui a été passé à la
> fonction.

Ok, là, ça fait aussi une sacrée différence avec le C.

> Par contre, si tu rebinde un paramètre, ça n'affecte que
> l'espace de nommage local. Exemple :

Et là, c'est un peu comme le C, mais pour des raisons différentes. Ok,
pour l'exemple. Merci, c'est très clair.

>> 2) Avec *Python*, une variable est un simple nom faisant référence à un
>> objet (avec un type [taille + façon d'être interprété],
>
> La notion de type est totalement différente.
>
> Selon les catégories du C, il n'existe qu'un seul type en Python, le
> type Py_Object_ptr, qui est un pointeur sur une structure de données
> (je parle bien sûr de l'implémentation CPython - en Jython ou
> IronPython, c'est probablement différent) (et bien sûr, je simplifie
> outrageusement).
>
> Selon la sémantique propre à Python, le 'type' d'un objet, c'est
> l'objet class (int, dict, function, etc) qu'il référence via son
> attribut __class__. A ce niveau, il n'y a pas de notion de 'taille',
> de 'façon d'être interprété' ou autre. Il y a juste une référence sur
> un autre objet dans lequel l'interpréteur ira chercher les attributs
> non trouvés dans l'objet lui-même.

D'accord, ça c'est d'un point de vue du langage abstrait. Tu
m'accorderas bien qu'un objet aura, in fine, une taille, une adresse et
une manière d'être interprété par la machine virtuelle Python. Non ?


>> Par exemple avec ceci (en Python)
>>
>> a=1
>> b=1
>> c=1
>>
>> finalement, dans la mémoire se trouve un seul objet créé (l'entier 1).
>
> Avec CPython, oui, mais parce que les petits entiers sont conservé en
> cache.

Heu, c'est quoi le cache ? Pour moi, c'est une sorte de mémoire RAM qui
est seulement plus rapide et moins volumineuse que la RAM classique.
Est-ce juste ?
Si oui, en quoi cela justifie que 1 se trouve en un seul endroit de la
mémoire ?

> Si tu remplace 1 par 33333, tu aura trois objets différents.

Et zut. Ça me chagrine un peu ça. En effet :

>>> a = 333333
>>> b = 333333
>>> id(a)
135973460
>>> id(b)
135973424

et donc la comparaison "id(a) == id(b)" n'est pas logiquement
équivalente à la comparaison "a==b". C'est dommage, non ?

Je pensais que si Python tombait sur une affectation d'un objet déjà
existant, il ne le récréait pas, mais faisait une référence à celui déjà
existant, cela dans le but de prendre moins de place dans la mémoire.
Pourquoi diable adopter cette stratégie quand on a des «petits» entiers,
et ne pas l'adopter pour des «gros» entiers ??? Je ne saisis pas bien la
logique là dedans ?


> Par contre, si tu fais:
>
> a = 33333
> b = a
> c = b
>
> Tu aura bien trois noms référençant un seul et même objet.

Ouf !


>> Remarque en passant : Je me doutais bien que d'un langage à un autre,
>> des mêmes notions pouvaient avoir une implémentation différente. Mais
>> quand même, je n'imaginais pas que cela serait le cas pour la basique
>> notion de variable par exemple !
>
> Attends de voir un langage fonctionnel pur (comme Haskell par
> exemple) : tu ne peux tout simplement pas modifier la valeur d'une
> variable une fois qu'elle est crée !-)

On laissera ça pour ... une autre vie :-)


>> J'espère que d'un langage à un autre,
>> il ne faut pas tout réapprendre à chaque fois (car là, finalement, j'ai
>> du réapprendre ce qu'est une variable :-) ) ?
>
> Non, la sémantique des variables de Python (de ce point de vue là) se
> retrouve, à l'identique ou de façon très proche, dans pas mal d'autres
> langages de haut niveau. De même que la sémantique des variables C se
> retrouve dans pas mal de langages de bas niveau.

Ouf !


>> Ok, ok. Allez, quand même, en interne de chez interne (dans le code C de
>> CPython par exemple), il n'y a pas de pointeur qui traîne quelque part
>> dans la définition d'une variable Python ? Hein, pour me faire plaisir. :-)
>
> Si, bien sûr. cf ci-dessus pour l'implémentation du type objet dans
> CPython. A vrai dire, y a même tellement de pointeurs que tu ne sais
> plus où donner de la tête. Content ?-)

Oui ! :-)


>>> En Python, tu n'a *que* des références sur des objets, *jamais* de
>>> types 'immédiat' comme en C. Ne laisse pas la syntaxe te tromper, ce
>>> n'est pas parce que tu définis un objet via une expression littérale
>>> que tu a autre chose qu'une référence sur un objet.
>> Heu, un type immédiat c'est quoi ?
>
> un entier en C.

Mais s'il y a *que* des références à des objets, cela veut dire que le
simple entier "1" en Python est un réalité un objet plus complexe qu'un
simple int ou char en C. Son codage binaire par exemple sera plus
complexe que le naturel "00000001" ?


--
François

Francois

unread,
Apr 8, 2008, 10:13:09 PM4/8/08
to
bruno.des...@gmail.com a écrit :

>> Bon, là j'exagère un peu. b[0]=7 est (je pense) une assignation du
>> premier élément de l'objet séquence référencé par a (ou par b),
>
> Dans la cas d'une liste, oui, on en arrive finalement à ça. Mais je
> pourrais écrire une classe telle que la même syntaxe n'effectue aucune
> assignation.

Je n'en doute pas. :-)


>> Cette réassignation, de fait, entraîne une modification de
>> l'objet séquence référencé par b et aussi par a.
>
> Tout à fait. Mais ne modifie pas l'espace de nommage en cours, et
> n'affecte pas les liaisons entre a et b et l'objet séquence (précision
> à l'adresse de l'OP).

Heu, OP, ça veut dire quoi ?


Merci encore pour toutes ces explications, fichtrement intéressantes.


--
François

Bruno Desthuilliers

unread,
Apr 9, 2008, 4:53:43 AM4/9/08
to
Francois a écrit :

> bruno.des...@gmail.com a écrit :
>> On 9 avr, 01:12, Francois <mathsatta...@free.fr> wrote:
(snip)

>>> Par exemple avec ceci (en Python)
>>>
>>> a=1
>>> b=1
>>> c=1
>>>
>>> finalement, dans la mémoire se trouve un seul objet créé (l'entier 1).
>>
>> Avec CPython, oui, mais parce que les petits entiers sont conservé en
>> cache.
>
> Heu, c'est quoi le cache ? Pour moi, c'est une sorte de mémoire RAM qui
> est seulement plus rapide et moins volumineuse que la RAM classique.
> Est-ce juste ?

Oui, mais sans aucun rapport - là tu parles du cache processeur !-)

Quand je dis que les petits entiers sont conservés en cache, je veux
dire que la machine virtuelle réserve une zone mémoire pour les stocker
au fur et à mesure de leur création, et quand le programme demande un
objet entier avec une valeur correspondante, c'est l'objet déjà créé qui
est retourné - ce qui évite d'en créer un nouveau. Comme ces objets sont
immutables, qu'on se contrefout de leur identité (on ne s'intéresse qu'à
leur valeur), et qu'un objet Python prend *beaucoup* plus de place (et
coûte beaucoup plus cher à créer) qu'un entier C, c'est une optimisation
évidente.

> Si oui, en quoi cela justifie que 1 se trouve en un seul endroit de la
> mémoire ?
>
>> Si tu remplace 1 par 33333, tu aura trois objets différents.
>
> Et zut. Ça me chagrine un peu ça. En effet :
>
> >>> a = 333333
> >>> b = 333333
> >>> id(a)
> 135973460
> >>> id(b)
> 135973424
>
> et donc la comparaison "id(a) == id(b)"

Qui s'exprime habituellement par l'opérateur d'identité 'is':

a is b <=> id(a) == id(b)

> n'est pas logiquement
> équivalente à la comparaison "a==b". C'est dommage, non ?

C'est le problème de la différence entre l'égalité (de valeur) et
l'identité. Selon les types, les deux peuvent être équivalents ou non.

Dis-toi bien que la grande majorité des objets sont 1/ mutables, et 2/
avec un état beaucoup plus complexe qu'une simple valeur. La notion
d'égalité de valeur est arbitraire (en ce qu'elle est définie par le
type), celle d'identité ne l'est pas (deux objets sont identiques si
c'est le même objet, point, barre).

> Je pensais que si Python tombait sur une affectation d'un objet déjà
> existant, il ne le récréait pas, mais faisait une référence à celui déjà
> existant, cela dans le but de prendre moins de place dans la mémoire.

a = [1, 2, 3]
b = [1, 2, 3]

A ce stade a et b sont égaux. Mais c'est accidentel. Doivent-ils être
identiques ? je peux vouloir modifier b sans modifier a

b[0] = 42

Si a et b avaient été identique, j'aurais, avec cette instruction,
modifié a également. Ainsi que toutes les autres listes de valeur
[1,2,3] existentes. Pas forcément ce que je voulais...

> Pourquoi diable adopter cette stratégie quand on a des «petits» entiers,
> et ne pas l'adopter pour des «gros» entiers ??? Je ne saisis pas bien la
> logique là dedans ?

Eviter de charger inutilement le cache. Les petits entiers sont
extrêmement utilisés, les gros nettemement moins. Accessoirement, la
'limite' à partir de laquelle les entiers ne sont plus cachés a évolué
récemment - en partie suite à l'évolution du hard. Tout ça est un détail
d'implémentation, point barre.

>
>> Par contre, si tu fais:
>>
>> a = 33333
>> b = a
>> c = b
>>
>> Tu aura bien trois noms référençant un seul et même objet.
>
> Ouf !
>
>
>>> Remarque en passant : Je me doutais bien que d'un langage à un autre,
>>> des mêmes notions pouvaient avoir une implémentation différente. Mais
>>> quand même, je n'imaginais pas que cela serait le cas pour la basique
>>> notion de variable par exemple !
>>
>> Attends de voir un langage fonctionnel pur (comme Haskell par
>> exemple) : tu ne peux tout simplement pas modifier la valeur d'une
>> variable une fois qu'elle est crée !-)
>
> On laissera ça pour ... une autre vie :-)

Pourquoi ? C'est intéressant aussi, comme approche, et il y a beaucoup à
en apprendre. Un des principes de la programmation fonctionnelle est
qu'une fonction ne doit pas avoir d'effets de bords (modifications de
l'état non-local) et que sa valeur (ce qu'elle retourne) ne doit
dépendre que et uniquement que de ses entrées (les paramètres qui lui
sont passés). Ce n'est pas toujours le plus efficace du point de vue des
ressources, mais ça aide (entre autres) à écrire des programmes faciles
à comprendre et maintenir. Bien qu'avant tout un langage objet, Python a
pas mal emprunté aussi à la programmation fonctionnelle, et tu verra pas
mal d'idiomes fonctionnels en Python.

C'est rien de le dire. A ton avis, pourquoi on les mets en cache ?

Tiens, si tu veux en savoir plus, essaie ça dans ton shell Python:

a = 1
for name in dir(a):
print name, " : ", getattr(a, name)

Et encore, les entiers (et quelques autres types 'builtin') ont une
implémentation spécifique pour raisons d'optimisation.

Tu peux aussi, bien sûr, aller lire le code source de CPython (c'est un
logiciel libre, n'est-ce pas...)

Bruno Desthuilliers

unread,
Apr 9, 2008, 5:53:26 AM4/9/08
to
Francois a écrit :
> bruno.des...@gmail.com a écrit :
(snip)

>> T'inquiètes pas, t'es pas le premier (et c'est pas non plus la
>> première fois que j'explique ça).
>
> Ah, désolé. Faut dire, à ma décharge, que tout cela n'est pas vraiment
> bien expliqué dans le peu de livres que j'ai.

Faudrait p'tet que j'en écrive un alors !-)

Plus sérieusement: vu la diversité de parcours de débutants en Python,
écrire un texte qui convienne à tous est une gageure.

Francois

unread,
Apr 9, 2008, 9:28:18 AM4/9/08
to Bruno Desthuilliers
Bruno Desthuilliers a écrit :

> C'est le problème de la différence entre l'égalité (de valeur) et
> l'identité. Selon les types, les deux peuvent être équivalents ou non.
>
> Dis-toi bien que la grande majorité des objets sont 1/ mutables, et 2/
> avec un état beaucoup plus complexe qu'une simple valeur. La notion
> d'égalité de valeur est arbitraire (en ce qu'elle est définie par le
> type), celle d'identité ne l'est pas (deux objets sont identiques si
> c'est le même objet, point, barre).
>
> [couic]

>
> a = [1, 2, 3]
> b = [1, 2, 3]
>
> A ce stade a et b sont égaux. Mais c'est accidentel. Doivent-ils être
> identiques ? je peux vouloir modifier b sans modifier a
>
> b[0] = 42
>
> Si a et b avaient été identique, j'aurais, avec cette instruction,
> modifié a également. Ainsi que toutes les autres listes de valeur
> [1,2,3] existentes. Pas forcément ce que je voulais...

Ok. J'ai l'impression qu'en gros, il faut retenir ceci :

Avec

a = <truc>
b = <truc>

(où <truc> est un objet) dans la grande majorité des cas (pour la
plupart des objets <truc>), a et b se réfèrent à des objets distincts.
C'est par exemple toujours le cas quand <truc> est un objet mutable.
Quand <truc> est un objet entier pas trop gros, où finalement seul sa
valeur nous intéresse et qui n'est pas mutable, alors dans ce cas
particulier a et b se réfèrent exactement au même objet qui se trouvera
dans le «cache». Mais, finalement, ce cas particulier est un *détail*.
Les raisons de ce détail, tu les as dites : un entier est non mutable
donc on se moque éperdument de son identité, autant prendre la même
quand l'entier est déjà créé avant. Quand l'entier est trop «gros», on
retombe dans le cas général pour ne pas encombrer le «cache». Mais
l'évolution du matériel tend à rendre la barre «entier trop gros» de
plus en plus haute. Mais là, on est dans des considérations
d'implémentation. Je m'arrête.

Est-ce correct ?

>>> Attends de voir un langage fonctionnel pur (comme Haskell par
>>> exemple) : tu ne peux tout simplement pas modifier la valeur d'une
>>> variable une fois qu'elle est crée !-)
>>
>> On laissera ça pour ... une autre vie :-)
>
> Pourquoi ? C'est intéressant aussi, comme approche, et il y a beaucoup à
> en apprendre.

Tu as raisons. Je disais ça parce que j'étais un peu fatigué. :-)


>> Mais s'il y a *que* des références à des objets, cela veut dire que le
>> simple entier "1" en Python est un réalité un objet plus complexe
>> qu'un simple int ou char en C. Son codage binaire par exemple sera
>> plus complexe que le naturel "00000001" ?
>
> C'est rien de le dire. A ton avis, pourquoi on les mets en cache ?
>
> Tiens, si tu veux en savoir plus, essaie ça dans ton shell Python:
>
> a = 1
> for name in dir(a):
> print name, " : ", getattr(a, name)

Je viens de le faire. Pfou !!! Effectivement, mon pauvre petit objet 1
est une usine à gaz à lui tout seul !!! Ça c'est l'impression générale.

En revanche, j'avoue ne pas comprendre exactement le résultat de ce
script. J'ai l'impression qu'en gros, on affiche tous les attributs de
l'objet référencé par a (d'après ce que j'ai cru comprendre en me
renseignant sur la fonction dir()). Pour moi, un attribut, c'est une
variable interne à l'objet. Donc, on peut afficher la valeur de
l'attribut en faisant a.attribut. Et bien, par exemple avec ceci :

>>> a = 1 # avec dir(a) je vois par exemple qu'il y a l'attribut __add__
>>> a.__add__
<method-wrapper '__add__' of int object at 0x816df38>

J'ai un résultat incompréhensible pour moi. C'est quoi ce résultat ? Ça
ne ressemble ni à un entier, ni une séquence etc.


Une autre chose me taraude. En C, une variable admet un contenu ou
valeur qui est codé(e) en binaire dans une zone contiguë de la mémoire.
En Python, cela a-t-il un sens de parler de contenu / valeur d'un objet
? J'en arrive à me dire que non.
- J'ai l'impression qu'on peut à la limite parler de contenu : un objet
dans la mémoire doit bien être stocké quelque part. En plus j'ai
l'impression que le stockage se fait dans des zones qui ne sont même pas
forcément contiguës.
- Mais je me demande si ça a toujours un sens de parler de valeur d'un
objet.

Par exemple, en C, je m'étais «amusé» à faire un tout petit programme
qui affiche le code binaire du contenu d'une variable. Est-ce possible
de faire la même chose en Python, c'est-à-dire afficher le code binaire
que contient un objet ? (si la question à un sens en Python)


--
François


PS : À un moment du parlais de "OP". Ça veut dire quoi ?

Francois

unread,
Apr 9, 2008, 9:29:09 AM4/9/08
to
Bruno Desthuilliers a écrit :

> C'est le problème de la différence entre l'égalité (de valeur) et
> l'identité. Selon les types, les deux peuvent être équivalents ou non.
>
> Dis-toi bien que la grande majorité des objets sont 1/ mutables, et 2/
> avec un état beaucoup plus complexe qu'une simple valeur. La notion
> d'égalité de valeur est arbitraire (en ce qu'elle est définie par le
> type), celle d'identité ne l'est pas (deux objets sont identiques si
> c'est le même objet, point, barre).
>
> [couic]

>
> a = [1, 2, 3]
> b = [1, 2, 3]
>
> A ce stade a et b sont égaux. Mais c'est accidentel. Doivent-ils être
> identiques ? je peux vouloir modifier b sans modifier a
>
> b[0] = 42
>
> Si a et b avaient été identique, j'aurais, avec cette instruction,
> modifié a également. Ainsi que toutes les autres listes de valeur
> [1,2,3] existentes. Pas forcément ce que je voulais...

Ok. J'ai l'impression qu'en gros, il faut retenir ceci :

Avec

a = <truc>
b = <truc>

(où <truc> est un objet) dans la grande majorité des cas (pour la
plupart des objets <truc>), a et b se réfèrent à des objets distincts.
C'est par exemple toujours le cas quand <truc> est un objet mutable.
Quand <truc> est un objet entier pas trop gros, où finalement seul sa
valeur nous intéresse et qui n'est pas mutable, alors dans ce cas
particulier a et b se réfèrent exactement au même objet qui se trouvera
dans le «cache». Mais, finalement, ce cas particulier est un *détail*.
Les raisons de ce détail, tu les as dites : un entier est non mutable
donc on se moque éperdument de son identité, autant prendre la même
quand l'entier est déjà créé avant. Quand l'entier est trop «gros», on
retombe dans le cas général pour ne pas encombrer le «cache». Mais
l'évolution du matériel tend à rendre la barre «entier trop gros» de
plus en plus haute. Mais là, on est dans des considérations
d'implémentation. Je m'arrête.

Est-ce correct ?

>>> Attends de voir un langage fonctionnel pur (comme Haskell par


>>> exemple) : tu ne peux tout simplement pas modifier la valeur d'une
>>> variable une fois qu'elle est crée !-)
>>
>> On laissera ça pour ... une autre vie :-)
>
> Pourquoi ? C'est intéressant aussi, comme approche, et il y a beaucoup à
> en apprendre.

Tu as raisons. Je disais ça parce que j'étais un peu fatigué. :-)


>> Mais s'il y a *que* des références à des objets, cela veut dire que le
>> simple entier "1" en Python est un réalité un objet plus complexe
>> qu'un simple int ou char en C. Son codage binaire par exemple sera
>> plus complexe que le naturel "00000001" ?
>
> C'est rien de le dire. A ton avis, pourquoi on les mets en cache ?
>
> Tiens, si tu veux en savoir plus, essaie ça dans ton shell Python:
>
> a = 1
> for name in dir(a):
> print name, " : ", getattr(a, name)

Je viens de le faire. Pfou !!! Effectivement, mon pauvre petit objet 1

Bruno Desthuilliers

unread,
Apr 9, 2008, 10:05:50 AM4/9/08
to
Francois a écrit :

> Bruno Desthuilliers a écrit :
>> C'est le problème de la différence entre l'égalité (de valeur) et
>> l'identité. Selon les types, les deux peuvent être équivalents ou non.
>>
>> Dis-toi bien que la grande majorité des objets sont 1/ mutables, et 2/
>> avec un état beaucoup plus complexe qu'une simple valeur. La notion
>> d'égalité de valeur est arbitraire (en ce qu'elle est définie par le
>> type), celle d'identité ne l'est pas (deux objets sont identiques si
>> c'est le même objet, point, barre).
>>
>> [couic]
>>
>> a = [1, 2, 3]
>> b = [1, 2, 3]
>>
>> A ce stade a et b sont égaux. Mais c'est accidentel. Doivent-ils être
>> identiques ? je peux vouloir modifier b sans modifier a
>>
>> b[0] = 42
>>
>> Si a et b avaient été identique, j'aurais, avec cette instruction,
>> modifié a également. Ainsi que toutes les autres listes de valeur
>> [1,2,3] existentes. Pas forcément ce que je voulais...
>
> Ok. J'ai l'impression qu'en gros, il faut retenir ceci :
>
> Avec
>
> a = <truc>
> b = <truc>
>
> (où <truc> est un objet) dans la grande majorité des cas (pour la
> plupart des objets <truc>), a et b se réfèrent à des objets distincts.

Attention: a = 1 est un sucre syntaxique pour a = int(1). Donc, c'est:

a = UneClasse()
b = UneClasse()

> C'est par exemple toujours le cas quand <truc> est un objet mutable.
> Quand <truc> est un objet entier pas trop gros, où finalement seul sa
> valeur nous intéresse et qui n'est pas mutable, alors dans ce cas
> particulier a et b se réfèrent exactement au même objet qui se trouvera
> dans le «cache». Mais, finalement, ce cas particulier est un *détail*.
> Les raisons de ce détail, tu les as dites : un entier est non mutable
> donc on se moque éperdument de son identité, autant prendre la même
> quand l'entier est déjà créé avant. Quand l'entier est trop «gros», on
> retombe dans le cas général pour ne pas encombrer le «cache». Mais
> l'évolution du matériel tend à rendre la barre «entier trop gros» de
> plus en plus haute. Mais là, on est dans des considérations
> d'implémentation. Je m'arrête.
>
> Est-ce correct ?

Minus la correction ci-dessus, oui.

>>> Mais s'il y a *que* des références à des objets, cela veut dire que
>>> le simple entier "1" en Python est un réalité un objet plus complexe
>>> qu'un simple int ou char en C. Son codage binaire par exemple sera
>>> plus complexe que le naturel "00000001" ?
>>
>> C'est rien de le dire. A ton avis, pourquoi on les mets en cache ?
>>
>> Tiens, si tu veux en savoir plus, essaie ça dans ton shell Python:
>>
>> a = 1
>> for name in dir(a):
>> print name, " : ", getattr(a, name)
>
> Je viens de le faire. Pfou !!! Effectivement, mon pauvre petit objet 1
> est une usine à gaz à lui tout seul !!!

Pour un entier, oui, ça relève de l'usine à gaz. Mais c'est le prix à
payer pour avoir une certaine uniformité (en l'occurrence, que tout ce
que tu peux manipuler en Python soit un objet).

> Ça c'est l'impression générale.
>
> En revanche, j'avoue ne pas comprendre exactement le résultat de ce
> script. J'ai l'impression qu'en gros, on affiche tous les attributs de
> l'objet référencé par a

A peu près tous (dir() ne retourne pas nécessairement l'intégralité des
attributs).

> (d'après ce que j'ai cru comprendre en me
> renseignant sur la fonction dir()). Pour moi, un attribut, c'est une
> variable interne à l'objet.

Un attribut, c'est un objet que tu peux atteindre depuis un autre objet
en utilisant la syntaxe objet.nom_attribut (ou son équivalent
getattr(objet, 'nom_attribut')).

> Donc, on peut afficher la valeur

la représentation, telle que définie par la méthode __repr__ de la
classe de l'attribut.

> de
> l'attribut en faisant a.attribut. Et bien, par exemple avec ceci :
>
> >>> a = 1 # avec dir(a) je vois par exemple qu'il y a l'attribut __add__
> >>> a.__add__
> <method-wrapper '__add__' of int object at 0x816df38>
>
> J'ai un résultat incompréhensible pour moi. C'est quoi ce résultat ? Ça
> ne ressemble ni à un entier, ni une séquence etc.

C'est une méthode. Un objet méthode. Rappelle-toi qu'en Python, *tout*
est objet - fonctions, méthodes, classes etc compris. Essaie aussi ça,
tant que tu y es:

def func(): pass
dir(func)

>
> Une autre chose me taraude. En C, une variable admet un contenu ou
> valeur qui est codé(e) en binaire dans une zone contiguë de la mémoire.
> En Python, cela a-t-il un sens de parler de contenu / valeur d'un objet
> ? J'en arrive à me dire que non.

Dans l'absolu, ça n'a effectivement aucun sens. Tout ce qu'un objet
'contien', ce sont des références sur d'autres objets.

> - J'ai l'impression qu'on peut à la limite parler de contenu : un objet
> dans la mémoire doit bien être stocké quelque part. En plus j'ai
> l'impression que le stockage se fait dans des zones qui ne sont même pas
> forcément contiguës.

Use the code, Luke.

> - Mais je me demande si ça a toujours un sens de parler de valeur d'un
> objet.

Tu peux considérer qu'en objet, globalement, valeur == état. Mais bon,
même en C, pour un char*, quelle est sa "valeur" ? l'adresse contenu
dans la variable, ou les données contenues à l'adresse contenue dans la
variable ?-) Et pour un pointeur sur un struct composé de pointeurs sur
des structs ? Quelle est sa "valeur" ?

> Par exemple, en C, je m'étais «amusé» à faire un tout petit programme
> qui affiche le code binaire du contenu d'une variable. Est-ce possible
> de faire la même chose en Python, c'est-à-dire afficher le code binaire
> que contient un objet ? (si la question à un sens en Python)

En Python, non, je ne vois pas comment tu pourrais faire une chose
pareille. En C, tu pourrais écrire une extension qui fasse une chose
similaire pour l'implémentation C des objets Python, mais ça n'aurait
aucun sens a priori.

Bruno Desthuilliers

unread,
Apr 9, 2008, 10:07:44 AM4/9/08
to
Francois a écrit :
(snip)

Attention, si tu mets le PS après la signature, la plupart des lecteurs
vont le faire sauter !-)

> PS : À un moment du parlais de "OP". Ça veut dire quoi ?

"Original Poster". Toi en l'occurrence.

Francois

unread,
Apr 9, 2008, 11:47:46 AM4/9/08
to
Bruno Desthuilliers a �crit :

> Attention: a = 1 est un sucre syntaxique pour a = int(1). Donc, c'est:
>
> a = UneClasse()
> b = UneClasse()

Arg ! Oui. Merci, de la rigueur, de la rigueur ! Il n'y a que comme �a
qu'on progresse. :-)


>> - J'ai l'impression qu'on peut � la limite parler de contenu : un
>> objet dans la m�moire doit bien �tre stock� quelque part. En plus j'ai
>> l'impression que le stockage se fait dans des zones qui ne sont m�me
>> pas forc�ment contigu�s.
>
> Use the code, Luke.

Je n'ai pas compris ? Peut-�tre une r�f�rence � Star Wars ? :-)


> Tu peux consid�rer qu'en objet, globalement, valeur == �tat. Mais bon,
> m�me en C, pour un char*, quelle est sa "valeur" ? l'adresse contenu
> dans la variable, ou les donn�es contenues � l'adresse contenue dans la
> variable ?-) Et pour un pointeur sur un struct compos� de pointeurs sur

> des structs ? Quelle est sa "valeur" ?

Pour le char*, j'aurais dit que la valeur est l'adresse contenu dans la
variable. Mais pour les autres ?


Bon, je crois que j'ai d�j� beaucoup abus� de ton temps. Je te remercie
mille fois pour ton aide pr�cieuse Bruno. J'�tais parti sur une mauvaise
pente avec mon approche � la C. Maintenant, gr�ce � toi, je pense �tre
dans la bonne direction. Mais il y a encore beaucoup de travail, ce qui
est normal.

Allez, juste une derni�re chose. As-tu des bonnes r�f�rences (livres,
docs en ligne etc. [je pr�f�re les livres, mais bon...]) � me proposer
sur Python ? En fait, ce que j'aimerais bien, c'est une pr�sentation
assez formelle, c'est-�-dire avec des d�finitions pr�cises, qui permette
de faire appara�tre la coh�rence du langage. En fait, je suis un matheux
� la base (mais je vais bien quand m�me :-) ). J'ai donc l'habitude
d'avoir des d�finitions pr�cises comme socle de d�part. C'est ce genre
de pr�sentation que j'aimerais bien trouver : un peu formelle et tr�s
rigoureuse, un peu comme en maths. J'avoue que dans ma modeste
exp�rience en apprentissage de langage, j'ai toujours �t� g�n� par le
manque de pr�cision des d�finitions. Par exemple, avec le C, je sentais
parfois qu'il y avait une terminologie rigoureuse, mais je trouvais les
d�finitions souvent assez floues et contradictoires parfois d'une source
� l'autre et finalement j'�tais un peu perdu.

\begin{digression}

Exemple concret de m�saventure personnelle : en C, je vois �crit :

- "objet = zone de stockage dans la m�moire"
- "variable = objet portant un nom"

Donc, j'en d�duis qu'un tableau est une variable. Je vais dans le fclc,
on me dit : "oui, oui un tableau est une variable". Tr�s bien. Je
regarde le K&R et j'y vois �cris noir sur blanc : "un tableau n'est pas
une variable". Je suis perdu. :-((

Une des rares doc que j'ai trouv�e qui a une approche assez rigoureuse
comme j'aime (enfin qui s'en rapproche le plus), c'est sur le net que je
l'ai trouv�e : "Introduction au langage C" de Bernard Cassagne. Il y
avait des trucs du genre :

� R�gle :
Tout identicateur de type "tableau de x" apparaissant dans une
expression est converti en une valeur constante dont :
- le type est "pointeur vers x" ;
- la valeur est l'adresse du premier �l�ment du tableau.�

Puis plein de petits exemples simples pour comprendre qu'effectivement
cette r�gle �tait vraiment bien appliqu�e � chaque fois, m�me dans t[2]
qui est converti en *(t+2) donc �a colle etc. �a m'avait bien plus et
bien aid� a comprendre.

\end{digression}

Bref, si tu as des r�f�rences un peu dans le style que j'ai essay� de
d�crire, �a m'int�resse. :-)

Pour l'instant, j'ai seulement : "Apprendre � programmer avec Python" de
Swinnen qui est *parfait pour commencer* je trouve. J'aimerais un truc
un peu plus formel maintenant.


Merci encore.

--
Fran�ois

Bruno Desthuilliers

unread,
Apr 10, 2008, 5:17:26 AM4/10/08
to
Francois a écrit :
> Bruno Desthuilliers a écrit :
>> Attention: a = 1 est un sucre syntaxique pour a = int(1). Donc, c'est:
>>
>> a = UneClasse()
>> b = UneClasse()
>
> Arg ! Oui. Merci, de la rigueur, de la rigueur ! Il n'y a que comme ça
> qu'on progresse. :-)
>
>
>>> - J'ai l'impression qu'on peut à la limite parler de contenu : un
>>> objet dans la mémoire doit bien être stocké quelque part. En plus
>>> j'ai l'impression que le stockage se fait dans des zones qui ne sont
>>> même pas forcément contiguës.
>>
>> Use the code, Luke.
>
> Je n'ai pas compris ? Peut-être une référence à Star Wars ? :-)
>

CPython est un logiciel libre, tu peux télécharger le code source (s'il
n'était pas déjà inclus dans ton installation de Python - ça dépend de
comment tu l'a installé) et le consulter. Le code source d'un logiciel
est toujours la documentation la plus exacte que tu puisse trouver (à
défaut d'être la plus facilement compréhensible !-).

Accessoirement, la doc de Python comprend une partie qui aborde
l'implémentation C.

>> Tu peux considérer qu'en objet, globalement, valeur == état. Mais bon,
>> même en C, pour un char*, quelle est sa "valeur" ? l'adresse contenu
>> dans la variable, ou les données contenues à l'adresse contenue dans
>> la variable ?-) Et pour un pointeur sur un struct composé de pointeurs

>> sur des structs ? Quelle est sa "valeur" ?
>
> Pour le char*, j'aurais dit que la valeur est l'adresse contenu dans la
> variable.

Ce qui est techniquement la bonne réponse. D'un autre côté, quand tu
l'utilise pour une chaine (ce qui est l'usage le plus courant de ce type
en C), la valeur utile est la chaine, pas l'adresse de son premier
élément...

> Mais pour les autres ?

Bin oui, pour les autres... Ce que je voulais dire, c'est que la notion
de "valeur" d'une variable n'est pas forcément si évidente à définir.

>
> Bon, je crois que j'ai déjà beaucoup abusé de ton temps.

Dans la mesure où personne n'est en train de me mettre un flingue sur la
tempe pour m'obliger à répondre, y a pas d'abus...

> Allez, juste une dernière chose. As-tu des bonnes références (livres,
> docs en ligne etc. [je préfère les livres, mais bon...]) à me proposer
> sur Python ? En fait, ce que j'aimerais bien, c'est une présentation
> assez formelle, c'est-à-dire avec des définitions précises, qui permette
> de faire apparaître la cohérence du langage.

Dans ce cas, le meilleur point de départ est la grammaire formelle du
langage.

> En fait, je suis un matheux

> à la base (mais je vais bien quand même :-) ). J'ai donc l'habitude
> d'avoir des définitions précises comme socle de départ. C'est ce genre
> de présentation que j'aimerais bien trouver : un peu formelle et très

> rigoureuse, un peu comme en maths.

=> grammaire du langage.

> J'avoue que dans ma modeste

> expérience en apprentissage de langage, j'ai toujours été gêné par le
> manque de précision des définitions.

Va falloir t'y faire. En général, il semble que les personnes avec une
forte culture mathématique soient plus attirées vers les langages
fonctionnels (Haskell, ML etc), ce "paradigme" étant un des seuls (avec
le modèle relationnel, utilisé dans les bases de données SQL) à découler
d'une théorie mathématique clairement définie. Les approches procédurale
et objet sont beaucoup plus informelle, et généralement plus prisées des
ingénieurs (obsevation sociologique qui ne s'appuie sur aucune étude
sérieuse, of course).

> Par exemple, avec le C, je sentais
> parfois qu'il y avait une terminologie rigoureuse, mais je trouvais les

> définitions souvent assez floues et contradictoires parfois d'une source
> à l'autre

Oui, c'est aussi un des problèmes : en l'absence d'une théorie claire et
bien établie, la terminologie est elle-même un peu floue, et la
polysémie est assez courante.

> Bref, si tu as des références un peu dans le style que j'ai essayé de
> décrire, ça m'intéresse. :-)
>
> Pour l'instant, j'ai seulement : "Apprendre à programmer avec Python" de

> Swinnen qui est *parfait pour commencer* je trouve. J'aimerais un truc
> un peu plus formel maintenant.

On en revient toujours au même point: les deux seules définitions
"formelles" d'un langage sont sa grammaire (quand il en existe une -
c'est heureusement le cas pour Python) et son implémentation.

Pour le reste, j'ai lu fort peu de livres sur Python, et je ne sais pas
si celui que tu cherches existe - la plupart de ceux que j'ai vu sont
plus orienté vers l'utilisation pratique que sur l'étude du formalisme
et du fonctionnement interne du langage. Tu peux regarder dans les
bouquins mentionnés sur python.org, mais je ne te garanti rien.

De toutes façons, tu a déjà toute la partie "language reference" de la
doc en ligne, ainsi que toute la partie sur les "new-style class". Ca
devrait t'occuper un certain temps !-)

Francois

unread,
Apr 10, 2008, 6:58:55 AM4/10/08
to
Quand tu parlais de Luke Skywalker, ça m'a fait penser à ce message que
j'ai vu quelque part sur le net et qui parait-il est un peu connu dans
le monde du Python. Je le trouve marrant. :-)

---------------------------------------------------
Comparaison de Perl et Python par Yoda

Sur la planète Dagobah.

Avec Yoda accroché dans son dos, Luke grimpe sur une des vignes qui
poussent dans le marais pour atteindre le laboratoire de statistiques de
Dagobah. Il y continue ses exercices, greppe, installe des nouveaux
paquets, se connecte en root, écrit des nouvelles versions de scripts en
Python pour remplacer des scripts Perl vieux de deux ans.

Yoda : Écris du code ! Oui. La force d’un programmeur découle de la
maintenabilité de son code. Mais méfies-toi de Perl ! Syntaxe laconique,
plus d’une manière de faire quelque chose ! Le côté obscur de la
maintenabilité Perl est. Si une seule fois par le chemin obscur tu
t’engages, pour toujours ta destinée sera marquée.

Luke : est-ce que Perl est mieux que Python ?

Yoda : non... non... non. Plus rapide, plus facile, plus séduisant.

Luke : mais comment saurais-je pourquoi Python est mieux que Perl ?

Yoda : tu sauras. Quand le code écrit il y a 6 mois de relire tu tenteras.
-----------------------------------------------------

Sinon, je garde dans un coin de ma tête tes remarques sur les langages
fonctionnels.

> Pour le reste, j'ai lu fort peu de livres sur Python, et je ne sais pas
> si celui que tu cherches existe - la plupart de ceux que j'ai vu sont
> plus orienté vers l'utilisation pratique que sur l'étude du formalisme
> et du fonctionnement interne du langage. Tu peux regarder dans les
> bouquins mentionnés sur python.org, mais je ne te garanti rien.
>
> De toutes façons, tu a déjà toute la partie "language reference" de la
> doc en ligne, ainsi que toute la partie sur les "new-style class". Ca
> devrait t'occuper un certain temps !-)

Très bien, Ça me fera travailler mon anglais un peu rouillé. :-)
Merci infiniment Bruno pour toutes tes réponses.

À bientôt...


--
François

Amaury Forgeot d'Arc

unread,
Apr 11, 2008, 4:26:14 PM4/11/08
to
Francois a écrit :

> Heu, OP, ça veut dire quoi ?

C'est du jargon de forum, tiré de l'anglais qui plus est:
Original Poster, ou bien "Orateur Primordial".

--
Amaury

Francois

unread,
Apr 11, 2008, 5:09:00 PM4/11/08
to
Amaury Forgeot d'Arc a écrit :

Merci. En fait, Bruno m'avait déjà répondu sur ce point. :-)

Petit à petit, on finit par connaître ces abréviations mais souvent on
ose pas demander. Par exemple, j'ai mis du temps pour comprendre "ÀMHA"
("à mon humble avis"). :-))


--
François

Jean-Baptiste renard

unread,
Apr 12, 2008, 4:43:15 PM4/12/08
to
Francois wrote:

Moi, j'ai une petite astuce. j'associe l'abbréviation avec le mot jargon
dans google. Ca fonctionne 99 fois sur 100 :)

exemple http://www.google.fr/search?q=jargon%20AMHA

Méta-MCI (MVP)

unread,
Apr 12, 2008, 5:16:04 PM4/12/08
to
Bonsoir !

En jargonnant sur Google, je suis tombé sur ça :
http://www2.cnrs.fr/presse/journal/2652.htm

C'est toi ?

@+

MCI

Jean-Baptiste renard

unread,
Apr 12, 2008, 6:37:09 PM4/12/08
to
Méta-MCI (MVP) wrote:
> En jargonnant sur Google, je suis tombé sur ça :
> http://www2.cnrs.fr/presse/journal/2652.htm
>
> C'est toi ?

Non, non.

BertrandB

unread,
May 1, 2008, 4:53:29 AM5/1/08
to
Bruno Desthuilliers a écrit :

Pourtant "Python Poésie" serait un bon titre

0 new messages