len - while python
¿Por qué el rango(inicio, final) no incluye el final? (8)
>>> 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?
Aunque hay algunas explicaciones algorítmicas útiles aquí, creo que puede ayudar agregar algunos razonamientos simples de la "vida real" en cuanto a por qué funciona de esta manera, lo que me parece útil al presentar el tema a los jóvenes recién llegados:
Con algo como ''rango (1,10)'', la confusión puede surgir al pensar que un par de parámetros representa el "comienzo y final".
En realidad es iniciar y "detener".
Ahora, si fuera el valor "final" entonces, sí, podría esperar que ese número se incluya como la entrada final en la secuencia. Pero no es el "fin".
Otros, erróneamente, llaman a ese parámetro "recuento" porque si solo usas el "rango (n)" entonces, por supuesto, itera ''n'' veces. Esta lógica se descompone al agregar el parámetro de inicio.
Así que el punto clave es recordar su nombre: " detener ". 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, mientras que "inicio" representa el primer valor que debe incluirse, al alcanzar el valor de "parada" 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, 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 parada / rendimiento / "ceder" y terminas sentándote en algún lugar al lado o detrás de tu auto. Técnicamente todavía no lo has alcanzado cuando te detienes. No está incluido en las ''cosas que pasaste en tu viaje''.
Espero que algo de eso ayude a explicar a Pythonitos / Pythonitas!
Básicamente, en el range(n)
Python range(n)
repite n
veces, lo cual es de naturaleza exclusiva por lo que no da el último valor cuando se imprime, podemos crear una función que otorga un valor inclusivo, lo que significa que también imprimirá el último valor mencionado en distancia.
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 yx
, que puede (como se ve arriba) iterar una vez más.
Lea los documentos de Python para conocer el rango, ya que consideran la iteración de bucle como la base de datos primaria.
Funciona bien en combinación con la 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 le dirá que es más Pythonic hacer for item in x
o for index, item in enumerate(x)
lugar de for i in range(len(x))
.
El corte 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 trabajar de la misma manera.
Lo considero como: "el primer número que desea, seguido del primer número que no quiere". Si desea 1-10, el primer número que no quiere es 11, por lo que 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 al range()
llamadas range()
.
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 le gusta la gama de Ruby:
1...11 #this is a range from 1 to 10
Sin embargo, Ruby reconoce que muchas veces querrá incluir el valor terminal y ofrece la sintaxis alternativa:
1..10 #this is also a range from 1 to 10
Las gamas exclusivas tienen algunos beneficios:
Por un lado, cada elemento en el range(0,n)
es un índice válido para listas de longitud n
.
También el range(0,n)
tiene una longitud de n
, no n+1
que sería un rango inclusivo.
Porque es más común llamar range(0, 10)
que devuelve [0,1,2,3,4,5,6,7,8,9]
que contiene 10 elementos que es igual a 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ías ver que si el range()
subiera exactamente a len(li)
esto sería problemático? El programador necesitaría restar explícitamente 1. Esto también sigue la tendencia común de los programadores que prefieren for(int i = 0; i < 10; i++)
en lugar for(int i = 0; i <= 9; i++)
.
Si está llamando 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]
También es útil para dividir rangos; range(a,b)
se puede dividir en range(a, x)
y range(x, b)
, mientras que con el rango inclusivo se escribiría x-1
o x+1
. Si bien rara vez necesita dividir rangos, tiende a dividir las listas con bastante frecuencia, lo cual es una de las razones por las que cortar una lista l[a:b]
incluye el elemento a-th pero no el b-th. Entonces el range
tiene la misma propiedad lo hace muy consistente.