Les slices

Tutoriel complet sur les slices en Python

a marqué ce sujet comme résolu.
Auteur du sujet

Bonjour à tous,

J'ai commencé (il y a 1 semaine, 1 jour) la rédaction d'un tutoriel dont l'intitulé est Les slices.

J'aimerais obtenir un maximum de retour sur celui-ci, sur le fond ainsi que sur la forme, afin de proposer en validation un texte de qualité.

Si vous êtes intéressé, cliquez ci-dessous

Merci d'avance pour votre aide

+4 -0

Génial ! Je te fais mes remarques sur le fond uniquement.

Introduction

Mots croisés

Mots croisés : une diagonale

Peut-être pourrais-tu essayer de ne mettre que le second schéma ? Là, ça fait beaucoup, surtout que les images sont de taille relativement importante.

C'est une grille de mots croisés dite parfaite, découverte en 2010 par Claude Coutanceau.

Je ne suis pas sûr qu'il soit judicieux d'en parler. Je ne crois pas que ça apporte d'information sur le tutoriel, et ce n'est pas très explicite. D'un autre côté, c'est un plus pour la culture générale.

Le tutoriel propose un exposé complet sur les slices en Python allant du plus élémentaire jusqu'à la construction de slices personnalisés.

Quid des pré-requis ? Il me semble nécessaire d'être au point sur la notion de collection/séquence.


Je vais lire le tutoriel en entier avant de le commenter, histoire d'avoir une vision globale sur ton travail. Juste un point tout de suite : je ne suis pas certain que les lettres x) au niveau des titres servent et, personnellement, je n'aime pas le rendu que ça donne.

Bon, un autre point : tu pourrais essayer de présenter les bouts de code comme s'ils sortaient de l'interpréteur. Le souci actuellement, c'est que l'affichage ne suit pas directement le print et donc quand il y en a plusieurs, ce n'est pas très pratique. Deux suggestions :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>> alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
>>> s = alpha[4:16]
>>> s
EFGHIJKLMNOP
>>> s[0]
E
>>> len(s)
12
>>> s.lower()
efghijklmnop
1
2
3
4
5
6
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
s = alpha[4:16]
print(s) # EFGHIJKLMNOP
print(s[0]) # E
print(len(s)) # 12
print(s.lower()) # efghijklmnop

D'ailleurs, tu peux, je pense, t'épargner de redéfinir alpha à chaque fois.

Merci. :)

Edit : j'ai rapidement lu le tutoriel et, en effet, il fournit un exposé complet, et clair. Par contre, j'ai eu l'impression d'avoir affaire à une énumération de propriétés, ce qui, en soi, n'est pas très attirant.

Je me demandais donc s'il ne serait pas préférable de ne pas organiser le tutoriel en fonction des propriétés, mais en fonction d'exemples. C'est en fait de cette manière que fonctionne nohar ici. L'idée serait d'avoir un ensemble de problèmes qu'on souhaite résoudre, résolution pour laquelle on aurait besoin des slices.

Ce n'est bien sûr qu'une suggestion.

PS : la licence du tutoriel est-elle un choix, ou juste un oubli lors de la création ? Simple question. ^^

Édité par Vayel

+0 -0
Auteur du sujet

Merci de ta lecture et de ton retour.

Peut-être pourrais-tu essayer de ne mettre que le second schéma ? Là, ça fait beaucoup, surtout que les images sont de taille relativement importante.

Oui, d'ailleurs je vais remanier l'intro.

C'est une grille de mots croisés dite parfaite, découverte en 2010 par Claude Coutanceau.

Je ne suis pas sûr qu'il soit judicieux d'en parler. Je ne crois pas que ça apporte d'information sur le tutoriel, et ce n'est pas très explicite. D'un autre côté, c'est un plus pour la culture générale.

OK

Quid des pré-requis ? Il me semble nécessaire d'être au point sur la notion de collection/séquence.

Ça va être difficile de trancher vu que les prérequis sont assez variables.

L'essentiel des trois premières sections se lit en sachant juste ce qu'est une liste ou une chaîne. Mais, il y a des exemples avec du code plus élaboré ou qui nécessite plus de maturité.

La dernière section suppose une connaissance plus approfondie de Python.


Je vais lire le tutoriel en entier avant de le commenter, histoire d'avoir une vision globale sur ton travail. Juste un point tout de suite : je ne suis pas certain que les lettres x) au niveau des titres servent et, personnellement, je n'aime pas le rendu que ça donne.

Je peux évoluer sur ce point.

Bon, un autre point : tu pourrais essayer de présenter les bouts de code comme s'ils sortaient de l'interpréteur.

Ça par contre, je ne le ferai pas ou à de très rares exceptions, déjà parce que je trouve ça moins clair de mélanger le code en entrée et les sorties correspondantes.

D'ailleurs, tu peux, je pense, t'épargner de redéfinir alpha à chaque fois.

Justement, je veux éviter que du code soit décontextualisé.

Edit : j'ai rapidement lu le tutoriel et, en effet, il fournit un exposé complet, et clair. Par contre, j'ai eu l'impression d'avoir affaire à une énumération de propriétés, ce qui, en soi, n'est pas très attirant.

(

Je me demandais donc s'il ne serait pas préférable de ne pas organiser le tutoriel en fonction des propriétés, mais en fonction d'exemples.

Remarque que je pars presque toujours d'exemples et que je donne beaucoup d'exemples. Simplement, je focalise sur mon sujet.

PS : la licence du tutoriel est-elle un choix, ou juste un oubli lors de la création ? Simple question. ^^

Comme le processus de dépôt de la version bêta ne m'a posé pas la question de la licence, je ne l'ai pas traitée ;) J'imagine que la question se posera lors de la publication après validation.

+0 -0

Salut,

Tuto un peu long pour le sujet traité, je crains que ça ne fasse fuir certains. En fait, je crois que j'ai un peu le même sentiment que Vayel : ce n'est pas attirant. C'est dommage, parce qu'il y a des passages vraiment très bien.

Sinon, un truc sur lequel j'ai tiqué :

Lorsqu'on effectue un slice t d'une séquence s, le contenu de s n'est jamais recopié ailleurs en mémoire, en toutes circonstance, que s soit mutable (une liste par exemple) ou pas (une chaîne, par exemple), que les éléments de s soient mutables ou pas. Ceci vaut pour tout type de slice, qu'il soit de base, étendu, sans ou avec indices implicites. Les contenus de s et de t réfèrent aux mêmes objets, simplement lors de la création de t des références vers les éléments du slice ont été créées. Autrement dit, une séquence s et un slice de s partagent les mêmes contenus.

Je ne vois pas très bien ce que tu cherche à dire par là. S'il s'agit d'un slice sur un conteneur (par ex. une liste), c'est valable aussi pour une copie par exemple (lst2 = list(lst1)), et c'est inhérent à la façon dont python gère les objets (une liste n'est finalement qu'une liste de références). Pour les chaines, c'est tout simplement faux, une nouvelle chaîne est crée et il n'y a aucun partage (logique, puisque une chaîne est immutable).

Preuve simple :

1
2
3
>>> s = 'azerty'
>>> s[1:-1] is s[1:-1]
False

En réalité, l'expérience montre que le coût de création d'un slice est peu élevé : probablement qu'en interne, le code de CPython gère de façon adroite le slice (après tout, cela ne nécessite de référencer que le debut et la fin du slice).

Non, il n'y a pas de copy-on-write sur les listes. (source)

+0 -0

Ça va être difficile de trancher vu que les prérequis sont assez variables.

Rien ne t'empêche d'indiquer des pré-requis pour chaque section. Le cas échéant, tu pourrais les placer dans un bloc information en début de chacune. ^^

Remarque que je pars presque toujours d'exemples et que je donne beaucoup d'exemples. Simplement, je focalise sur mon sujet.

Tout à fait. Il faudrait que j'y réfléchisse plus en détail pour te fournir des propositions plus exploitables, mais peut-être pourrais-tu essayer de prendre des exemples plus concrets ? Je vais relire le tutoriel dans cette optique.

Comme le processus de dépôt de la version bêta ne m'a posé pas la question de la licence, je ne l'ai pas traitée ;) J'imagine que la question se posera lors de la publication après validation.

La licence se choisit à la création du tutoriel, sous le bloc dédié à la conclusion. Tu peux la changer en éditant le tutoriel, comme tu le fais pour l'introduction.

+1 -0
Auteur du sujet

Tuto un peu long pour le sujet traité,

Oui, j'en ai conscience.

Sinon, un truc sur lequel j'ai tiqué :

Je ne vois pas très bien ce que tu cherche à dire par là.

A mettre en garde contre ce que le terme de "copie (superficielle)" peut faire penser : il n'ya pas de copie (visible).

S'il s'agit d'un slice sur un conteneur (par ex. une liste), c'est valable aussi pour une copie par exemple (lst2 = list(lst1)),

Oui

et c'est inhérent à la façon dont python gère les objets (une liste n'est finalement qu'une liste de références).

Absolument.

Pour les chaines, c'est tout simplement faux, une nouvelle chaîne est crée et il n'y a aucun partage (logique, puisque une chaîne est immutable).

Bon, on ne parle pas de la même chose. Pour reprendre ton exemple, ce que je dis c'est ceci :

1
2
3
4
5
6
>>> s = 'azerty'
>>> a=s[1:-1]
>>> b=s[1:-1]
>>> all((u is v) for (u,v) in zip(a,b))
True
>>> 

D'ailleurs, je ne sais pas pourquoi ton exemple se limite aux chaînes, c'est vrai pour n'importe quel slice de n'importe quelle séquence, mutable ou pas :

1
2
3
4
>>> L=list('azerty')
>>> L[1:-1] is L[1:-1]
False
>>> 

Non, il n'y a pas de copy-on-write sur les listes. [(source)]

C'est exactement ce que je dis depuis le début, les contenus ne sont pas copiés. Par contre, il faut bien qu'en interne la liste soit créée autrement dit que le slice sache où sont les objets qu'il référence, donc on peut imaginer qu'il y a copie de références (de pointeurs dans CPython). D'ailleurs, si tu regardes le code source vers lequel pointe la référence de SO que tu cites toi-même, tu verras qu'il semble bien y avoir explicitement copie de références, cf. le source de CPython.

D'ailleurs, d'autres posts sur SO vont dans le sens de mon interprétation, par exemple Does Python copy references to objects when slicing a list?

Malgré mes efforts de clarté, visiblement, je me suis mal fait comprendre :(

+0 -0

Super tutoriel assez complet. Merci à l'auteur.

En le parcourant, je rejoins l'avis de certains qui pensent qu'il est très long … pour un mini tutoriel. Je pense qu'il devrait plutôt être présenté sous forme de big tutoriel avec 1 seule partie et 4 chapitres en dessous "Slices de base", "Slides étendus", "Modifier avec des slices" et "Slices avancés".

ça permettra au lecteur de lire plus facilement le cours. On évitera donc aux débutants de se sentir perdus dans tout ce flot (oh combien intéressant) d'information.

+0 -0

Bon, on ne parle pas de la même chose. Pour reprendre ton exemple, ce que je dis c'est ceci :

1
2
3
4
5
>>> s = 'azerty'
>>> a=s[1:-1]
>>> b=s[1:-1]
>>> all((u is v) for (u,v) in zip(a,b))
True

C'est une illusion due au fait que python cache certains caractères (les 256 premier chez moi).

1
2
3
4
5
>>> s = ''.join(chr(x) for x in range(1000,1000+10))
>>> a = s[1:-1]
>>> b = s[1:-1]
>>> all((u is v) for (u,v) in zip(a,b))
False

D'ailleurs, je ne sais pas pourquoi ton exemple se limite aux chaînes, c'est vrai pour n'importe quel slice de n'importe quelle séquence, mutable ou pas :

Effectivement, mon exemple est foireux. Ce que j'essaie de faire comprendre, c'est simplement qu'une chaîne n'est pas un conteneur ni une séquence au sens habituel du terme. Il n'y a pas de type char en python, et s[0] va créer une nouvelle chaîne, exactement comme s[1:-1]. Bref, il n'y a aucune copie de référence dans le cas d'un slice sur une chaine, parce qu'une chaine ne contient aucune référence. Du reste, tu remarqueras que la sémantique de __contains__ n'a rien à voir selon si elle est appliquée à une chaine ou une liste.

Non, il n'y a pas de copy-on-write sur les listes. [(source)]

C'est exactement ce que je dis depuis le début, les contenus ne sont pas copiés. Par contre, il faut bien qu'en interne la liste soit créée autrement dit que le slice sache où sont les objets qu'il référence, donc on peut imaginer qu'il y a copie de références (de pointeurs dans CPython). D'ailleurs, si tu regardes le code source vers lequel pointe la référence de SO que tu cites toi-même, tu verras qu'il semble bien y avoir explicitement copie de références, cf. le source de CPython.

J'ai dû mal comprendre ta phrase. Il m'a semblé que tu voulais dire que la liste (le container) n'est pas réellement copiée mais partagée entre la liste source et le slice. Ce qui est faux.

+0 -0
Auteur du sujet

C'est une illusion due au fait que python cache certains caractères (les 256 premier chez moi).

Exact.

```pycon

s = ''.join(chr(x) for x in range(1000,1000+10)) a = s[1:-1] b = s[1:-1] all((u is v) for (u,v) in zip(a,b)) False

Je t'avoue que ton code me plonge encore dans un océan de perplexité … Le problème est que le comportement de Python est ici presque aberrant . Poussons ton exemple plus loin :

1
2
3
4
5
6
7
8
>>> D=1000
>>> s = ''.join(chr(x) for x in range(D,D+3))
>>> print(s)
ϨϩϪ
>>> a=s
>>> a is s
True
>>> 

Jusque là, tout va bien : a n'est qu'un alias de s, ils forment un seul et même objet. On s'attend donc que les objets a[0] et s[0] soient identiques… et bien non ! :

1
2
3
>>> a[0] is s[0]
False
>>>

Et donc, on essaye de comprendre et de regarder les id, et là encore big big surprise :

1
2
3
>>> id(a[0]) == id(s[0])
True
>>>

Ton contre-exemple est parfaitement intéressant mais je n'en tirerais aucune conclusion car si tu considères qu'un slice de chaîne effectue une copie alors tu dois considérer qu'une simple affectation de chaîne fait aussi une copie, ce qui n'est jamais le cas en Python, suivant des sources fiables, par ex. N. Batchelder ou surtout R. Hettinger qui est un core developper qui a créé les descripteurs, itertools, etc bref qui connait parfaitement Python.

+0 -0

Je t'avoue que ton code me plonge encore dans un océan de perplexité … Le problème est que le comportement de Python est ici presque aberrant . Poussons ton exemple plus loin :

1
2
3
4
5
6
7
8
>>> D=1000
>>> s = ''.join(chr(x) for x in range(D,D+3))
>>> print(s)
ϨϩϪ
>>> a=s
>>> a is s
True
>>> 

Jusque là, tout va bien : a n'est qu'un alias de s, ils forment un seul et même objet. On s'attend donc que les objets a[0] et s[0] soient identiques… et bien non ! :

1
2
3
>>> a[0] is s[0]
False
>>>

Et donc, on essaye de comprendre et de regarder les id, et là encore big big surprise :

1
2
3
>>> id(a[0]) == id(s[0])
True
>>>

Je suis autant surpris que toi, mais pour la raison exactement opposée :p . Pour moi, c'est le retour de id(a[0]) == id(s[0]) qui est surprenant, pas le premier. Ceci pour la raison que j'ai donné plus haut, un accès sur une chaine crée une nouvelle chaine, du coup ceci est parfaitement "logique" :

1
2
>>> a[0] is a[0]
False

Pour le comportement avec id, il faut que je creuse, mais il est possible que ceci soit une explication. D'ailleurs :

1
2
3
4
5
6
>>> a0_1 = a[0]
>>> a0_2 = a[0]
>>> a0_1 is a0_2
False
>>> id(a0_1) == id(a0_2)
False

Ton contre-exemple est parfaitement intéressant mais je n'en tirerais aucune conclusion car si tu considères qu'un slice de chaîne effectue une copie alors tu dois considérer qu'une simple affectation de chaîne fait aussi une copie, ce qui n'est jamais le cas en Python, suivant des sources fiables, par ex. N. Batchelder ou surtout R. Hettinger qui est un core developper qui a créé les descripteurs, itertools, etc bref qui connait parfaitement Python.

Non, je ne vois pas du tout en quoi ceci implique cela. Il n'y a pas d'affectation de chaine (ni quoi que ce soit d'autre d'ailleurs) en python, juste affectation de référence, donc lorsque tu fais a = s tu crées nécessairement un alias. En revanche, le comportement d'un slice est systématiquement de créer un nouvel objet du même type que le sliceable. C'est d'ailleurs pour ça que l'idiome pour copier une liste est : lst2 = lst1[:].

Édité par yoch

+0 -0
Auteur du sujet

J'ai largement simplifié et allégé cette nouvelle version, renvoyé en annexe les choses non essentielles mais que je voulais garder pour avoir un traitement complet. L'objection de yosh s'avère finalement pleinement justifiée : toute accès à un caractère unicode d'ordinal > 256 d'une chaîne recrée ce caractère (lire le code-source de str.getitem de CPython) et j'ai donc rectifié en conséquence.

+0 -0
Auteur du sujet

Oui, j'avais d'ailleurs considéré ta proposition avec intérêt dès le début. Dans la solution actuelle j'ai drastiquement élagué le corps du tuto et les sections 1 et 2 (le coeur du sujet) sont devenues raisonnables en taille ce qui m'a semblé ne plus justifier le big-tuto. Mais sinon, on pourrait donc faire section i = chapitre i. Mais quid des annexes ? qui ne sont pas en état de faire un chapitre cohérent, peut être pourrais-je en extraire de quoi faire juste un chapitre 4. Et il me faudra faire encore une annexe. Je trouve les annexes très pratiques : on n'est pas obligé d'y aller mais c'est utile à certains.

+0 -0

Cette réponse a aidé l’auteur du sujet

Salut,

J'ai relu la première partie, c'est effectivement plus fluide. 2 petites remarques :

  • nom[-4:]=='.py' => c'est nom[-3:]
  • d'instructions ²for² ou ²if² => ??

Édité par yoch

+0 -0
Auteur du sujet

Après plusieurs relectures qui ont entraîné de nombreuses corrections, mon travail est parti pour la validation. Merci aux intervenants de cette discussion de leur remarques et conseils et de l'intérêt qu'ils ont porté au document.

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte