>>> range(1,11)
vous donne
[1,2,3,4,5,6,7,8,9,10]
Pourquoi pas 1-11?
Ont-ils simplement décidé de le faire comme ça au hasard ou cela a-t-il une valeur que je ne vois pas?
range()
a beaucoup plus de sens
>>> range(1,11)
vous donne
[1,2,3,4,5,6,7,8,9,10]
Pourquoi pas 1-11?
Ont-ils simplement décidé de le faire comme ça au hasard ou cela a-t-il une valeur que je ne vois pas?
range()
a beaucoup plus de sens
Réponses:
Parce qu'il est plus courant d'appeler range(0, 10)
qui renvoie [0,1,2,3,4,5,6,7,8,9]
qui contient 10 éléments ce qui équivaut len(range(0, 10))
. N'oubliez pas que les programmeurs préfèrent l'indexation basée sur 0.
Considérez également l'extrait de code commun suivant:
for i in range(len(li)):
pass
Pouvez-vous voir que si cela range()
montait exactement len(li)
, ce serait problématique? Le programmeur aurait besoin de soustraire explicitement 1. Il suit également la tendance commune des programmeurs préférant for(int i = 0; i < 10; i++)
plus for(int i = 0; i <= 9; i++)
.
Si vous appelez fréquemment une plage avec un début de 1, vous pouvez définir votre propre fonction:
>>> def range1(start, end):
... return range(start, end+1)
...
>>> range1(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
range(start, count)
?
range(10)
-à- dire qu'elle est équivalente à range(0, 10)
.
range1
ne fonctionnera pas avec des plages qui ont une taille de pas différente de celle 1
.
for i in range(len(li)):
est plutôt un contre-modèle. Il faut utiliser enumerate
.
Bien qu'il y ait quelques explications algorithmiques utiles ici, je pense qu'il peut être utile d'ajouter un raisonnement simple `` dans la vraie vie '' pour expliquer pourquoi cela fonctionne de cette façon, que j'ai trouvé utile lors de l'introduction du sujet aux jeunes nouveaux arrivants:
Avec quelque chose comme «range (1,10)», la confusion peut provenir du fait de penser qu'une paire de paramètres représente le «début et la fin».
C'est en fait démarrer et "arrêter".
Maintenant, s'il s'agissait de la valeur "end", alors, vous pourriez vous attendre à ce que ce nombre soit inclus comme entrée finale dans la séquence. Mais ce n'est pas la "fin".
D'autres appellent par erreur ce paramètre "count" car si vous n'utilisez que "range (n)", alors, bien sûr, il itère "n" fois. Cette logique tombe en panne lorsque vous ajoutez le paramètre de démarrage.
Le point clé est donc de se souvenir de son nom: " stop ". Cela signifie que c'est le point auquel, une fois atteinte, l'itération s'arrêtera immédiatement. Pas après ce point.
Ainsi, alors que "start" représente en effet la première valeur à inclure, en atteignant la valeur "stop", il "casse" plutôt que de continuer à traiter "celle-là aussi" avant de s'arrêter.
Une analogie que j'ai utilisée pour expliquer cela aux enfants est que, ironiquement, il vaut mieux se comporter que les enfants! Cela ne s'arrête pas après qu'il était censé le faire - il s'arrête immédiatement sans terminer ce qu'il faisait. (Ils obtiennent ceci;))
Une autre analogie - lorsque vous conduisez une voiture, vous ne passez pas un panneau d'arrêt / de rendement / de «passage» et vous vous retrouvez avec quelque part à côté ou derrière votre voiture. Techniquement, vous ne l'avez toujours pas atteint lorsque vous vous arrêtez. Il n'est pas inclus dans les «choses que vous avez transmises pendant votre voyage».
J'espère que cela aide à expliquer à Pythonitos / Pythonitas!
Il fonctionne bien en combinaison avec l'indexation de base zéro et len()
. Par exemple, si vous avez 10 éléments dans une liste x
, ils sont numérotés de 0 à 9. range(len(x))
vous donne 0-9.
Bien sûr, les gens vous diront que c'est plus Pythonic à faire for item in x
ou for index, item in enumerate(x)
plutôt que for i in range(len(x))
.
Le découpage fonctionne de cette façon aussi: les foo[1:4]
éléments 1 à 3 de foo
(en gardant à l'esprit que l'élément 1 est en fait le deuxième élément en raison de l'indexation à base zéro). Par souci de cohérence, ils devraient tous deux fonctionner de la même manière.
Je pense à cela comme: "le premier numéro que vous voulez, suivi du premier numéro que vous ne voulez pas ." Si vous voulez 1-10, le premier nombre que vous ne voulez pas est 11, donc c'est range(1, 11)
.
Si cela devient lourd dans une application particulière, il est assez facile d'écrire une petite fonction d'aide qui ajoute 1 à l'index de fin et aux appels range()
.
w = 'abc'; w[:] == w[0:len(w)]; w[:-1] == w[0:len(w)-1];
def full_range(start,stop): return range(start,stop+1) ## helper function
for index, item in enumerate(x)
pour éviter toute confusion
Il est également utile pour fractionner des plages; range(a,b)
peut être divisé en range(a, x)
et range(x, b)
, alors qu'avec une plage inclusive, vous écririez soit x-1
ou x+1
. Bien que vous ayez rarement besoin de fractionner des plages, vous avez tendance à fractionner des listes assez souvent, ce qui est l'une des raisons pour lesquelles le découpage d'une liste l[a:b]
comprend le a-ème élément mais pas le b-ème. Le fait d' range
avoir la même propriété le rend bien cohérent.
La longueur de la plage est la valeur supérieure moins la valeur inférieure.
C'est très similaire à quelque chose comme:
for (var i = 1; i < 11; i++) {
//i goes from 1 to 10 in here
}
dans un langage de style C.
Également comme la gamme Ruby:
1...11 #this is a range from 1 to 10
Cependant, Ruby reconnaît que plusieurs fois vous voudrez inclure la valeur du terminal et propose la syntaxe alternative:
1..10 #this is also a range from 1 to 10
1..10
vs 1...10
est difficile à distinguer lors de la lecture de code!
Fondamentalement, en python, range(n)
itère les n
temps, ce qui est de nature exclusive, c'est pourquoi il ne donne pas la dernière valeur lorsqu'il est imprimé, nous pouvons créer une fonction qui donne une valeur inclusive, cela signifie qu'il imprimera également la dernière valeur mentionnée dans la plage.
def main():
for i in inclusive_range(25):
print(i, sep=" ")
def inclusive_range(*args):
numargs = len(args)
if numargs == 0:
raise TypeError("you need to write at least a value")
elif numargs == 1:
stop = args[0]
start = 0
step = 1
elif numargs == 2:
(start, stop) = args
step = 1
elif numargs == 3:
(start, stop, step) = args
else:
raise TypeError("Inclusive range was expected at most 3 arguments,got {}".format(numargs))
i = start
while i <= stop:
yield i
i += step
if __name__ == "__main__":
main()
Considérez le code
for i in range(10):
print "You'll see this 10 times", i
L'idée est que vous obtenez une liste de longueur y-x
, que vous pouvez (comme vous le voyez ci-dessus) parcourir.
Lisez les documents python pour la plage - ils considèrent l'itération pour la boucle comme la principale utilisation.
Il est juste plus pratique de raisonner dans de nombreux cas.
Fondamentalement, nous pourrions penser à une plage comme un intervalle entre start
et end
. Si start <= end
, la longueur de l'intervalle entre eux est end - start
. Si len
était réellement défini comme la longueur, vous auriez:
len(range(start, end)) == start - end
Cependant, nous comptons les entiers inclus dans la plage au lieu de mesurer la longueur de l'intervalle. Pour conserver la propriété ci-dessus vraie, nous devons inclure l'un des points de terminaison et exclure l'autre.
Ajouter le step
paramètre revient à introduire une unité de longueur. Dans ce cas, vous vous attendez
len(range(start, end, step)) == (start - end) / step
pour la longueur. Pour obtenir le nombre, vous utilisez simplement la division entière.