>>> range(1,11)
te dio
[1,2,3,4,5,6,7,8,9,10]
¿Por qué no 1-11?
¿Simplemente decidieron hacerlo así al azar o tiene algún valor que no estoy viendo?
range()
tiene mucho más sentido
>>> range(1,11)
te dio
[1,2,3,4,5,6,7,8,9,10]
¿Por qué no 1-11?
¿Simplemente decidieron hacerlo así al azar o tiene algún valor que no estoy viendo?
range()
tiene mucho más sentido
Respuestas:
Porque es más común llamar a range(0, 10)
return [0,1,2,3,4,5,6,7,8,9]
que contiene 10 elementos que son iguales len(range(0, 10))
. Recuerde que los programadores prefieren la indexación basada en 0.
Además, considere el siguiente fragmento de código común:
for i in range(len(li)):
pass
¿Podría ver que si range()
fuera exactamente len(li)
eso sería problemático? El programador tendría que restar explícitamente 1. Esto también sigue la tendencia común de los programadores prefieren for(int i = 0; i < 10; i++)
más for(int i = 0; i <= 9; i++)
.
Si llama al rango con un inicio de 1 con frecuencia, es posible que desee definir su propia función:
>>> 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)
es decir, es equivalente a range(0, 10)
.
range1
no va a funcionar con rangos que tienen un tamaño de paso diferente a 1
.
for i in range(len(li)):
Es más bien un antipatrón. Uno debería usar enumerate
.
Aunque hay algunas explicaciones algorítmicas útiles aquí, creo que puede ayudar agregar un razonamiento simple de la `` vida real '' sobre por qué funciona de esta manera, lo que he encontrado útil al presentar el tema a los recién llegados:
Con algo como 'rango (1,10)' puede surgir confusión al pensar que un par de parámetros representa el "inicio y el final".
En realidad es comenzar y "parar".
Ahora, si fuera el valor "final", entonces, sí, es de esperar que ese número se incluya como la entrada final en la secuencia. Pero no es el "fin".
Otros llaman erróneamente a ese parámetro "cuenta" porque si solo usa 'range (n)', entonces, por supuesto, itera 'n' veces. Esta lógica se rompe cuando agrega el parámetro de inicio.
Entonces, el punto clave es recordar su nombre: " stop ". Eso significa que es el punto en el que, cuando se alcanza, la iteración se detendrá de inmediato. No después de ese punto.
Entonces, si bien "inicio" representa el primer valor que se incluirá, al alcanzar el valor de "detención" se "rompe" en lugar de continuar procesando "ese también" antes de detenerse.
Una analogía que he usado para explicar esto a los niños es que, irónicamente, ¡se comporta mejor que los niños! No se detiene después de lo que se supone que debe hacerlo; se detiene inmediatamente sin terminar lo que estaba haciendo. (Consiguen esto;))
Otra analogía: cuando conduces un automóvil no pasas una señal de alto / rendimiento / 'ceder' y terminas sentado en algún lugar al lado o detrás de tu automóvil. Técnicamente todavía no lo has alcanzado cuando te detienes. No está incluido en las "cosas que pasó en su viaje".
¡Espero que algo de eso ayude a explicar a Pythonitos / Pythonitas!
Funciona bien en combinación con indexación basada en cero y len()
. Por ejemplo, si tiene 10 elementos en una lista x
, están numerados del 0 al 9. range(len(x))
te da 0-9.
Por supuesto, la gente te dirá que es más Pythonic hacer for item in x
o for index, item in enumerate(x)
no for i in range(len(x))
.
La división también funciona de esa manera: foo[1:4]
son los elementos 1-3 de foo
(teniendo en cuenta que el elemento 1 es en realidad el segundo elemento debido a la indexación basada en cero). Por coherencia, ambos deberían funcionar de la misma manera.
Pienso en ello como: "el primer número que desea, seguido del primer número que no desea". Si quieres 1-10, el primer número que no quieres es 11, entonces es range(1, 11)
.
Si se vuelve engorroso en una aplicación en particular, es bastante fácil escribir una pequeña función auxiliar que agregue 1 al índice final y las llamadas 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)
para evitar confusiones
También es útil para dividir rangos; range(a,b)
se puede dividir en range(a, x)
y range(x, b)
, mientras que con un rango inclusivo escribiría x-1
o x+1
. Si bien rara vez necesita dividir rangos, tiende a dividir las listas con bastante frecuencia, que es una de las razones por las que dividir una lista l[a:b]
incluye el elemento a-th pero no el b-th. Entonces range
tener la misma propiedad lo hace muy consistente.
La longitud del rango es el valor superior menos el valor inferior.
Es muy similar a algo como:
for (var i = 1; i < 11; i++) {
//i goes from 1 to 10 in here
}
en un lenguaje de estilo C.
También como la gama de Ruby:
1...11 #this is a range from 1 to 10
Sin embargo, Ruby reconoce que muchas veces querrás incluir el valor del terminal y ofrece la sintaxis alternativa:
1..10 #this is also a range from 1 to 10
1..10
vs 1...10
siendo difícil distinguir entre el momento de lectura de códigos!
Básicamente, en python range(n)
itera n
veces, lo cual es de naturaleza exclusiva, por eso no da el último valor cuando se imprime, podemos crear una función que proporcione un valor inclusivo, lo que significa que también imprimirá el último valor mencionado en el rango.
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()
Considera el código
for i in range(10):
print "You'll see this 10 times", i
La idea es que obtenga una lista de longitud y-x
, que puede (como puede ver arriba) repetir.
Lea sobre los documentos de Python para el rango: consideran que la iteración de bucle es el caso de uso principal.
Es más conveniente razonar sobre esto en muchos casos.
Básicamente, podríamos pensar en un rango como un intervalo entre start
y end
. Si start <= end
, la longitud del intervalo entre ellos es end - start
. Si en len
realidad se definiera como la longitud, tendrías:
len(range(start, end)) == start - end
Sin embargo, contamos los enteros incluidos en el rango en lugar de medir la longitud del intervalo. Para mantener verdadera la propiedad anterior, debemos incluir uno de los puntos finales y excluir el otro.
Agregar el step
parámetro es como introducir una unidad de longitud. En ese caso, esperarías
len(range(start, end, step)) == (start - end) / step
por longitud. Para obtener el recuento, solo usa la división de enteros.