>>> range(1,11)
ti dà
[1,2,3,4,5,6,7,8,9,10]
Perché non 1-11?
Hanno appena deciso di farlo in modo casuale o ha un valore che non vedo?
range()
ha un senso molto più spesso
>>> range(1,11)
ti dà
[1,2,3,4,5,6,7,8,9,10]
Perché non 1-11?
Hanno appena deciso di farlo in modo casuale o ha un valore che non vedo?
range()
ha un senso molto più spesso
Risposte:
Perché è più comune chiamare range(0, 10)
che restituisce [0,1,2,3,4,5,6,7,8,9]
che contiene 10 elementi uguali len(range(0, 10))
. Ricorda che i programmatori preferiscono l'indicizzazione basata su 0.
Inoltre, considera il seguente frammento di codice comune:
for i in range(len(li)):
pass
Potresti vedere che se range()
si arrivasse esattamente a len(li)
questo sarebbe problematico? Il programmatore avrebbe bisogno di sottrarre in modo esplicito 1. La presente segue anche la tendenza comune di programmatori preferendo for(int i = 0; i < 10; i++)
sopra for(int i = 0; i <= 9; i++)
.
Se stai chiamando l'intervallo con un inizio di 1 frequentemente, potresti voler definire la tua funzione:
>>> 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)
è equivalente a range(0, 10)
.
range1
non funzionerà con intervalli che hanno una dimensione del gradino diversa da 1
.
for i in range(len(li)):
è piuttosto un antipasto. Uno dovrebbe usare enumerate
.
Sebbene ci siano alcune utili spiegazioni algoritmiche qui, penso che possa aiutare ad aggiungere alcuni semplici ragionamenti sulla "vita reale" sul perché funziona in questo modo, che ho trovato utile quando ho presentato l'argomento ai giovani nuovi arrivati:
Con qualcosa come 'range (1,10)' la confusione può derivare dal pensare che la coppia di parametri rappresenti "inizio e fine".
In realtà è start e "stop".
Ora, se fosse il valore di "fine" allora sì, ci si potrebbe aspettare che il numero sarebbe stato incluso come la voce finale della sequenza. Ma non è la "fine".
Altri erroneamente chiamano quel parametro "count" perché se usi sempre 'range (n)' allora, ovviamente, itera 'n' volte. Questa logica si interrompe quando si aggiunge il parametro start.
Quindi il punto chiave è ricordare il suo nome: " stop ". Ciò significa che è il punto in cui, una volta raggiunta, l'iterazione si interromperà immediatamente. Non dopo quel punto.
Pertanto, sebbene "start" rappresenti effettivamente il primo valore da includere, al raggiungimento del valore "stop" esso "si interrompe" anziché continuare a elaborare "anche quello" prima di arrestarsi.
Un'analogia che ho usato per spiegare questo ai bambini è che, ironicamente, si comporta meglio dei bambini! Non si ferma dopo che dovrebbe - si ferma immediatamente senza finire quello che stava facendo. (Ottengono questo;))
Un'altra analogia: quando si guida un'auto non si passa un segnale di stop / yield / "cedere" e si finisce con esso seduto da qualche parte accanto o dietro l'auto. Tecnicamente non l'hai ancora raggiunto quando ti fermi. Non è incluso nelle "cose che hai passato nel tuo viaggio".
Spero che questo aiuti a spiegare a Pythonitos / Pythonitas!
Funziona bene in combinazione con indicizzazione a base zero e len()
. Ad esempio, se in un elenco x
sono presenti 10 voci , queste sono numerate da 0 a 9. range(len(x))
ti dà 0-9.
Naturalmente, le persone ti diranno che è più Pythonic da fare for item in x
o for index, item in enumerate(x)
piuttosto che for i in range(len(x))
.
Anche l'affettare funziona in questo modo: foo[1:4]
sono gli articoli 1-3 di foo
(tenendo presente che l'articolo 1 è in realtà il secondo oggetto a causa dell'indicizzazione in base zero). Per coerenza, entrambi dovrebbero funzionare allo stesso modo.
Lo penso come: "il primo numero che vuoi, seguito dal primo numero che non vuoi". Se vuoi 1-10, il primo numero che non vuoi è 11, quindi è range(1, 11)
.
Se diventa ingombrante in una particolare applicazione, è abbastanza facile scrivere una piccola funzione di aiuto che aggiunge 1 all'indice finale e chiama 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)
per evitare confusione
È anche utile per dividere gli intervalli; range(a,b)
può essere suddiviso in range(a, x)
e range(x, b)
, mentre con un intervallo inclusivo scriverebbe x-1
o x+1
. Mentre raramente hai bisogno di dividere gli intervalli, tendi a dividere gli elenchi abbastanza spesso, il che è uno dei motivi per cui un elenco l[a:b]
include l'elemento a-th ma non il b-th. Quindi range
avere la stessa proprietà lo rende piacevolmente coerente.
La lunghezza dell'intervallo è il valore superiore meno il valore inferiore.
È molto simile a qualcosa del tipo:
for (var i = 1; i < 11; i++) {
//i goes from 1 to 10 in here
}
in un linguaggio di tipo C.
Piace anche la gamma di Ruby:
1...11 #this is a range from 1 to 10
Tuttavia, Ruby riconosce che molte volte vorrai includere il valore del terminale e offre la sintassi alternativa:
1..10 #this is also a range from 1 to 10
1..10
vs 1...10
essere difficile distinguere tra quando si legge il codice!
Fondamentalmente nei tempi di range(n)
iterazione di Python n
, che è di natura esclusiva ed è per questo che non dà l'ultimo valore quando viene stampato, possiamo creare una funzione che dia valore inclusivo significa che stamperà anche l'ultimo valore menzionato nell'intervallo.
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 il codice
for i in range(10):
print "You'll see this 10 times", i
L'idea è che ottieni un elenco di lunghezza y-x
, che puoi (come vedi sopra) scorrere più volte.
Leggi i documenti di Python per range - considerano l'iterazione for-loop la base utente principale.
In molti casi è solo più conveniente ragionare.
Fondamentalmente, potremmo pensare a un intervallo come a un intervallo tra start
e end
. Se start <= end
la lunghezza dell'intervallo tra loro è end - start
. Se len
fosse effettivamente definito come lunghezza, avresti:
len(range(start, end)) == start - end
Tuttavia, contiamo gli interi inclusi nell'intervallo invece di misurare la lunghezza dell'intervallo. Per mantenere vera la proprietà di cui sopra, dovremmo includere uno degli endpoint ed escludere l'altro.
Aggiungere il step
parametro è come introdurre un'unità di lunghezza. In tal caso, ti aspetteresti
len(range(start, end, step)) == (start - end) / step
per lunghezza. Per ottenere il conteggio, basta usare la divisione intera.